Study on the go with our IT certification podcast
Tune in to Linux tips, security hardening walkthroughs, and exam strategies while commuting or working out. New episodes weekly.
Listen on SpotifyCourse Modules
01
Linux Foundations & Boot Process
5 lessons · ~4 hours
Linux Foundations & Boot Process
5 lessons · ~4 hours
Every Linux+ scenario starts with the same chain: firmware → bootloader → kernel → initramfs → systemd → userspace. Get this graph in your head and "the server hangs at boot" or "kernel panic — unable to mount root" stop being mysteries and become a question of which link broke. Module 01 walks each link end to end — from BIOS/UEFI through GRUB2 rescue mode, systemd targets, initramfs rebuilds, and kernel module wiring.
Linux Distributions & Architecture
Kernel, Shell, Userspace & FHS
- The Linux kernel manages hardware resources: CPU scheduling, memory management, device drivers, and system calls
- The shell (bash, zsh, sh) is the user-facing interpreter that parses commands and communicates with the kernel via system calls
- Userspace contains all processes running outside the kernel — daemons, applications, and libraries (glibc)
- The Filesystem Hierarchy Standard (FHS) defines the directory tree:
/bin(essential binaries),/sbin(system binaries),/etc(config files),/var(variable data),/usr(user programs),/tmp(temporary),/proc(kernel/process virtual FS),/sys(device/driver info) - Major distro families: Red Hat (RHEL, CentOS, Fedora, Rocky, AlmaLinux) — RPM/DNF; Debian (Ubuntu, Mint) — DEB/APT; SUSE (openSUSE, SLES) — RPM/Zypper; Arch — Pacman
The Linux+ exam tests cross-distro knowledge. Understand both RPM-based and DEB-based package managers. RHEL derivatives dominate enterprise environments, so RPM/DNF commands get heavier exam weight.
BIOS/UEFI Boot Process & GRUB2
Boot Sequence
- BIOS/UEFI performs POST (Power-On Self-Test), initializes hardware, then loads the bootloader from MBR (BIOS) or EFI partition (UEFI)
- GRUB2 (GRand Unified Bootloader v2) is the standard Linux bootloader — loads the kernel and initramfs into memory
- GRUB2 config location:
/boot/grub2/grub.cfg(RHEL/Fedora) or/boot/grub/grub.cfg(Debian/Ubuntu) - Never edit
grub.cfgdirectly — edit/etc/default/gruband regenerate withgrub2-mkconfig -o /boot/grub2/grub.cfg - Key
/etc/default/grubparameters:GRUB_TIMEOUT(menu delay),GRUB_CMDLINE_LINUX(kernel parameters),GRUB_DEFAULT(default entry)
GRUB2 Rescue Mode
- If GRUB fails to find its modules, you drop to
grub rescue>prompt grub rescue> ls— list detected partitions (e.g.,(hd0,gpt1),(hd0,gpt2))grub rescue> ls (hd0,gpt2)/— check for/boot/grub2/directorygrub rescue> set root=(hd0,gpt2)— set the root partitiongrub rescue> set prefix=(hd0,gpt2)/boot/grub2— point to GRUB modulesgrub rescue> insmod normalthengrub rescue> normal— load normal GRUB mode
The exam tests the grub.cfg location — it is
/boot/grub2/grub.cfg on RHEL/CentOS systems. Always regenerate with grub2-mkconfig after editing /etc/default/grub. Editing grub.cfg directly is wrong — changes are overwritten on update.💻 Worked scenario — GRUB2 rescue recovery
A disk swap leaves the server at a grub rescue> prompt. Recovery sequence: (1) ls to list detected partitions — look for the one containing /boot/grub2/ (e.g. (hd0,gpt2)); (2) set root=(hd0,gpt2); (3) set prefix=(hd0,gpt2)/boot/grub2; (4) insmod normal then normal — GRUB loads its full menu; (5) boot into the OS, then fix permanently: edit /etc/default/grub as needed and run grub2-mkconfig -o /boot/grub2/grub.cfg. Verify: grep menuentry /boot/grub2/grub.cfg shows the boot entries.
Systemd Boot Targets
Targets Replace SysV Runlevels
poweroff.target— runlevel 0, system haltrescue.target— runlevel 1 / single-user mode; minimal services, root shell for recoverymulti-user.target— runlevel 3; full multi-user, no GUI; standard for serversgraphical.target— runlevel 5; multi-user with desktop environmentreboot.target— runlevel 6, system restartsystemctl get-default— view current default targetsystemctl set-default multi-user.target— change default target persistentlysystemctl isolate rescue.target— switch to rescue mode immediately (non-persistent)
To boot into a specific target temporarily, append
systemd.unit=rescue.target to the kernel command line in GRUB. This is the standard recovery technique for forgotten root passwords alongside rd.break.initramfs & Early Userspace
Purpose of initramfs
- The initramfs (initial RAM filesystem) is a compressed cpio archive loaded into memory at boot before the real root filesystem is mounted
- It provides the minimal tools needed to: load kernel modules for storage controllers, set up LVM/RAID, unlock encrypted volumes, and mount the real root filesystem
- Lives at
/boot/initramfs-$(uname -r).img(RHEL) or/boot/initrd.img-$(uname -r)(Debian)
Rebuilding initramfs
- RHEL/Fedora:
dracut --force /boot/initramfs-$(uname -r).img $(uname -r) - Debian/Ubuntu:
update-initramfs -u -k $(uname -r) - Necessary after: adding kernel modules to initramfs, changing storage drivers, modifying
/etc/crypttab lsinitrd /boot/initramfs-$(uname -r).img | less— inspect initramfs contents (RHEL)
If a system fails to boot after adding an encrypted disk or new storage controller, rebuilding the initramfs with
dracut --force (RHEL) or update-initramfs -u (Debian) is often the fix. The exam tests which tool to use per distro family.Kernel Modules
Module Management Commands
lsmod— list currently loaded kernel modules and their dependenciesmodinfo MODULE— display module metadata: description, author, parameters, filenamemodprobe MODULE— load a module and its dependencies automaticallymodprobe -r MODULE— remove (unload) a module and unused dependenciesrmmod MODULE— remove a module directly (does not handle dependencies)insmod /path/to/module.ko— insert a module by file path (no dependency resolution)
Persistent Module Configuration
/etc/modprobe.d/— directory for module configuration files (e.g., aliases, options, blacklisting)- Blacklist a module: create
/etc/modprobe.d/blacklist-MODULE.confwithblacklist MODULE - Set module options:
options MODULE param=valuein a conf file under/etc/modprobe.d/ - Modules to load at boot: list names in
/etc/modules-load.d/*.conffiles
Use
modprobe over insmod in almost all cases — modprobe resolves dependencies automatically. insmod requires the full path and won't load required dependencies first.Key takeaways
- BIOS/UEFI hands control to GRUB2, which loads
vmlinuz+initramfs; never editgrub.cfgby hand — change/etc/default/grubthen rungrub2-mkconfig -o /boot/grub2/grub.cfg. - SysV runlevels are gone — systemd targets replace them (
multi-user.target,graphical.target,rescue.target). Switch withsystemctl isolate; persist withsystemctl set-default. - After any storage / encryption change, rebuild the initramfs —
dracut --forceon RHEL,update-initramfs -uon Debian — and prefermodprobeoverinsmodfor kernel modules (dependency resolution included).
⚡ Mini-quiz — Drill the boot chain, GRUB2 rescue, systemd targets, and module commands.
Quick quiz →
02
Package Management & Software
5 lessons · ~4 hours
Package Management & Software
5 lessons · ~4 hours
Linux+ is a cross-distro exam, so a single question can quiz rpm, dnf, apt, zypper, and even
./configure && make in five answer choices. The trick is to learn each package manager as a small verb table — install · remove · search · update · query · verify — and memorise the one or two flags that diverge per family. Module 02 builds that table for RHEL/Fedora, Debian/Ubuntu, SUSE, and source compiles.
RPM-Based Package Management
rpm Command Essentials
rpm -ivh package.rpm— install a package (-i) with verbose output (-v) and progress bar (-h)rpm -Uvh package.rpm— upgrade a package (installs if not present)rpm -e PACKAGENAME— erase (remove) an installed packagerpm -qa— query all installed packages; combine withgrepto searchrpm -qi PACKAGENAME— detailed info about an installed packagerpm -ql PACKAGENAME— list files owned by an installed packagerpm -qf /path/to/file— which package owns a given filerpm -V PACKAGENAME— verify package integrity (checks checksums, permissions, ownership)rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release— import a GPG signing key
rpm -V output codes: S=file size changed, M=mode changed, 5=MD5 checksum mismatch, U=user ownership changed. A dot (.) means no change. This is a frequently tested command on the Linux+ exam.DNF / YUM Package Manager
Common DNF Commands
dnf install PACKAGE— install a package and resolve dependenciesdnf remove PACKAGE— remove a packagednf update— update all packages to latest available versionsdnf update PACKAGE— update a specific packagednf search KEYWORD— search for packages by name or descriptiondnf info PACKAGE— show detailed package metadatadnf provides /path/to/file— find which package provides a file or commanddnf history— show transaction history;dnf history undo Nreverses transaction Ndnf group install "Development Tools"— install a package groupdnf repolist— list enabled repositories
Repository Configuration
- Repo files live in
/etc/yum.repos.d/with.repoextension - Key fields:
[repo-id],name,baseurlormirrorlist,enabled=1,gpgcheck=1,gpgkey= dnf config-manager --add-repo URL— add a new repositorydnf config-manager --enable REPO_ID/--disable REPO_ID— toggle repos
Know the difference:
dnf update refreshes and installs newer package versions; dnf upgrade is an alias. dnf check-update lists available updates without installing them. Also: yum is the legacy name — on modern RHEL 8+ systems it is a symlink to dnf.💻 Worked scenario — package lifecycle with history rollback
Task: identify which package provides /usr/bin/iostat, install it, verify, then roll it back. Walk: (1) dnf provides /usr/bin/iostat → shows sysstat; (2) dnf install sysstat; (3) rpm -ql sysstat | grep iostat confirms the binary is installed; (4) dnf history → note the transaction ID (e.g. 47); (5) dnf history info 47 to inspect what was changed; (6) dnf history undo 47 removes the package cleanly. This sequence also tests repos: if dnf provides returns nothing, dnf repolist and check that the right repo is enabled.
DEB-Based Package Management
dpkg Command Essentials
dpkg -i package.deb— install a .deb package filedpkg -r PACKAGENAME— remove a package (keeps config files)dpkg -P PACKAGENAME— purge a package (removes config files too)dpkg -l— list all installed packages with status codesdpkg -L PACKAGENAME— list files installed by a packagedpkg -S /path/to/file— which package owns a given filedpkg --get-selections | grep PACKAGENAME— check package installation status
APT Package Manager
apt update— refresh the local package index (downloads metadata from repos)apt upgrade— install available package updatesapt install PACKAGE— install a package with dependenciesapt remove PACKAGE— remove package, keep config;apt purge PACKAGEremoves config tooapt autoremove— remove packages that were installed as dependencies but are no longer neededapt search KEYWORD— search packages;apt-cache search KEYWORD(older syntax)apt show PACKAGE— show package details- Repo sources:
/etc/apt/sources.listand/etc/apt/sources.list.d/*.list
apt update only refreshes the local package cache — it does NOT install any updates. apt upgrade installs the available updates. This two-step pattern is a classic exam question. Always run apt update before apt install on a freshly started system.Zypper (SUSE) Package Manager
Core Zypper Commands
zypper install PACKAGE(orzypper in PACKAGE) — install a packagezypper remove PACKAGE(orzypper rm PACKAGE) — remove a packagezypper update(orzypper up) — update installed packageszypper search KEYWORD(orzypper se KEYWORD) — search for packageszypper info PACKAGE— display detailed package informationzypper repos(orzypper lr) — list configured repositorieszypper addrepo URL ALIAS— add a new repositoryzypper refresh(orzypper ref) — refresh repository metadata
Zypper is SUSE/openSUSE-specific. The Linux+ exam may include one or two Zypper questions. Focus on the short-form aliases (
in, rm, up, se, lr) as they appear in practical scenarios.Compiling from Source
The Classic Build Workflow
- Download source tarball:
wget https://example.com/app-1.0.tar.gzthentar -xzf app-1.0.tar.gz ./configure— checks for required build dependencies, sets compile options, generatesMakefile./configure --prefix=/usr/local— install to a custom directory (default is/usr/local)make— compiles the source code using the generated Makefilemake install— installs compiled binaries to the prefix directorymake uninstall— remove installed files (if the Makefile supports it)
Build Dependencies
- Common required packages:
gcc,make,autoconf,automake,libtool,kernel-devel - On RHEL:
dnf groupinstall "Development Tools"installs the full toolchain - On Debian:
apt install build-essential - Missing header errors during
./configuremean a-devel/-devpackage is not installed
If
./configure fails with "missing library", install the corresponding -devel package (RHEL) or -dev package (Debian). The configure script reports the exact missing dependency in its error output.Key takeaways
- RHEL family:
dnf install/remove/update/search; query the installed DB withrpm -qa,rpm -ql,rpm -V;dnf history+dnf history undo <id>rolls back transactions. - Debian family:
apt updateonly refreshes the cache,apt upgradeinstalls it — always run them as a pair.dpkg -ifor local.debfiles,apt --fix-broken installrepairs dependency hell. - SUSE uses
zypperwith short aliases (in,rm,up,se,lr); source compiles always follow./configure → make → make installand need a-devel/-devpackage per missing header.
⚡ Mini-quiz — Drill the cross-distro verb table: install, query, verify, history, rollback.
Quick quiz →
03
User, Group & Permission Management
6 lessons · ~5 hours
User, Group & Permission Management
6 lessons · ~5 hours
The UNIX permission model is small — three subjects (user / group / other), three actions (read / write / execute), four files (
/etc/passwd, /etc/shadow, /etc/group, /etc/gshadow) — and then layered on top: special bits (setuid, setgid, sticky), POSIX ACLs for extra entries, and PAM for the login policy. Module 03 covers everything from useradd to setfacl, plus the password-policy levers the exam loves to test.
User & Group Administration
User Account Commands
useradd USERNAME— create a new user; add-mto create home dir,-s /bin/bashto set shell,-u UIDfor specific UIDusermod -aG GROUP USERNAME— add user to a supplementary group (-ais critical — appends instead of replacing)usermod -s /sbin/nologin USERNAME— disable login shell for a service accountuserdel USERNAME— delete a user;userdel -r USERNAMEalso removes home directory and mail spoolid USERNAME— display UID, GID, and all supplementary groups for a user
Group Commands & Key Files
groupadd GROUPNAME— create a new group;groupmod -n NEWNAME OLDNAME— rename;groupdel GROUPNAME— deletenewgrp GROUPNAME— switch active primary group in the current session without logging out/etc/passwd— format:username:x:UID:GID:comment:home:shell/etc/shadow— format:username:hashed_password:last_change:min:max:warn:inactive:expire/etc/group— format:groupname:x:GID:member1,member2
The
-a flag with usermod -G is critical. Running usermod -G GROUP USER without -a REPLACES all supplementary groups with only the specified group — this is a classic misconfiguration that locks users out of shared resources.💻 Worked scenario — service account with exact UID and group
Task: create svc-monitor with UID 3001, no interactive login, added to the monitoring group without disrupting other memberships. Walk: (1) useradd -u 3001 -s /sbin/nologin svc-monitor; (2) groupadd monitoring (if the group doesn't exist); (3) usermod -aG monitoring svc-monitor — the -a is mandatory, omitting it silently wipes all other supplementary groups; (4) verify: id svc-monitor shows UID=3001 and includes the monitoring GID; (5) grep svc-monitor /etc/passwd confirms the shell is /sbin/nologin. Attempting su - svc-monitor as root should say "This account is currently not available."
Password Policies & PAM
passwd and chage
passwd USERNAME— set or change a user's password;passwd -l USERNAMElocks,passwd -u USERNAMEunlockschage -M 90 USERNAME— set maximum password age to 90 dayschage -m 7 USERNAME— set minimum days before password can be changedchage -W 14 USERNAME— warn user 14 days before password expirationchage -E 2026-12-31 USERNAME— set account expiration datechage -l USERNAME— list all aging information for a user
PAM & Password Complexity
- PAM (Pluggable Authentication Modules) controls authentication via
/etc/pam.d/config files pam_pwqualitymodule enforces password complexity (length, uppercase, digits, special characters)- Configure in
/etc/security/pwquality.conf:minlen=12,ucredit=-1,dcredit=-1,ocredit=-1 /etc/login.defs— system-wide defaults:PASS_MAX_DAYS,PASS_MIN_DAYS,PASS_WARN_AGE,UID_MIN,UID_MAX
PAM modules are evaluated in order within each service file. The four control flags are:
required (must pass, continues), requisite (must pass, stops on fail), sufficient (if pass, no further required checks), optional (result ignored unless only module).Standard Linux Permissions
chmod, chown, chgrp
- Permission bits: owner (u), group (g), others (o); each has read (r=4), write (w=2), execute (x=1)
chmod 755 file— numeric: owner rwx (7), group r-x (5), others r-x (5)chmod u+x,g-w file— symbolic: add execute to owner, remove write from groupchmod -R 750 /dir— recursive permission changechown USER:GROUP file— change owner and group;chown USER file— change owner onlychgrp GROUP file— change group ownership only
umask
umaskdefines default permissions by masking bits from 666 (files) and 777 (directories)- Default umask
022: files get 644 (rw-r--r--), directories get 755 (rwxr-xr-x) umask 027: files get 640, directories get 750 — more restrictive, suitable for shared servers- Set persistently in
/etc/bashrcor~/.bashrc
For umask calculation: subtract the umask from the base permissions. File base = 666, directory base = 777. umask 027 on a file: 666 - 027 = 640 (rw-r-----). This subtraction method is what the exam tests.
Special Permission Bits
SUID, SGID, and Sticky Bit
- SUID (Set User ID) — on an executable: the process runs as the file owner, not the invoking user. Example:
/usr/bin/passwdruns as root. Set withchmod 4755 fileorchmod u+s file - SGID (Set Group ID) — on an executable: process runs with the file's group. On a directory: new files/directories inherit the directory's group (not the creator's primary group). Set with
chmod 2755 fileorchmod g+s dir - Sticky Bit — on a directory: only the file owner, directory owner, or root can delete/rename files within it, even if others have write permission. Classic use:
/tmp. Set withchmod 1777 dirorchmod +t dir - Display:
ls -lshowssin place ofxfor SUID/SGID,tin place ofxfor sticky bit in others position
SUID on a directory has no standard effect — it is SGID on directories that causes group inheritance. The exam tests SGID on directories specifically as a mechanism for shared project directories where all files should belong to the project group.
Access Control Lists (ACLs)
setfacl and getfacl
getfacl file— display the full ACL for a file or directorysetfacl -m u:USERNAME:rwx file— grant a specific user rwx on a filesetfacl -m g:GROUPNAME:r-- file— grant a group read-only accesssetfacl -x u:USERNAME file— remove a user's ACL entrysetfacl -b file— remove all ACL entries (except base permissions)setfacl -m mask::r-- file— set the effective rights mask (limits maximum ACL permissions)
Default ACLs for Directories
setfacl -d -m u:USERNAME:rwx /dir— set a default ACL (-d): new files/directories created inside inherit this ACL- A
+sign inls -loutput indicates ACL entries beyond standard permissions are set - Filesystem must be mounted with ACL support; ext4 and XFS support ACLs natively; check with
tune2fs -l /dev/sdX | grep "Default mount"
The ACL mask acts as a maximum effective permission ceiling for all named users and groups (but NOT the file owner or other). Even if you grant a user rwx via ACL, the mask can reduce the effective permission to just read. Run
getfacl to see effective permissions after mask application.Key takeaways
- User state lives in
/etc/passwd+/etc/shadow+/etc/group; mutate it throughuseradd,usermod,passwd,chage— never by hand-editing those files in production. - Standard mode (
rwxrwxrwx) covers 90% of cases; reach for special bits (SUIDfor privileged binaries,SGIDon directories for shared-group inheritance, sticky on/tmp) and POSIX ACLs (setfacl) only when the owner/group/other triad is too narrow. - Password policy is set through PAM (
/etc/pam.d/stacks) plus/etc/login.defs;umaskdrives default permissions on new files (file base 666, dir base 777, minus umask).
⚡ Mini-quiz — Drill
Quick quiz →
chmod math, special bits on dirs, ACL mask behaviour, and PAM stack order.
04
Storage & Filesystems
6 lessons · ~5 hours
Storage & Filesystems
6 lessons · ~5 hours
Storage on Linux is layered: block device → partition → (LVM) → filesystem → mountpoint, with optional RAID at the block layer and LUKS for encryption anywhere in the stack. Module 04 walks each layer with the tool that owns it —
fdisk/parted/gdisk for partitions, mkfs.* + mount + /etc/fstab for filesystems, pvcreate/vgcreate/lvcreate for LVM, mdadm for RAID, cryptsetup for LUKS, and mkswap/swapon for swap.
Partitioning: fdisk, parted & gdisk
Partition Table Types
- MBR (Master Boot Record) — legacy; max 4 primary partitions or 3 primary + 1 extended (with logical partitions); max disk size 2 TB
- GPT (GUID Partition Table) — modern; supports up to 128 partitions per disk; required for disks over 2 TB; used with UEFI
fdisk /dev/sdX— interactive MBR partition editor;n(new),d(delete),t(change type),w(write),q(quit)gdisk /dev/sdX— interactive GPT partition editor (same command letters as fdisk)parted /dev/sdX— supports both MBR and GPT; non-interactive mode:parted /dev/sdX mklabel gptlsblk— list block devices and partition layout;blkid— show UUIDs and filesystem types
Use
fdisk for MBR disks up to 2 TB. For GPT or disks larger than 2 TB, use gdisk or parted. The exam will present scenarios requiring you to identify the correct partitioning tool based on disk size and UEFI vs BIOS context.Filesystem Creation & Mounting
Creating Filesystems
mkfs.ext4 /dev/sdX1— format a partition as ext4;-L LABELto add a volume labelmkfs.xfs /dev/sdX1— format as XFS (default on RHEL 7+)tune2fs -L NEWLABEL /dev/sdX1— change ext2/3/4 volume label;tune2fs -c 50— set max mount count before fsckxfs_admin -L NEWLABEL /dev/sdX1— change XFS volume labele2fsck -f /dev/sdX1— check and repair an ext filesystem (must be unmounted)xfs_repair /dev/sdX1— check and repair an XFS filesystem (must be unmounted)
Mounting & /etc/fstab
mount /dev/sdX1 /mnt/data— mount temporarily;mount -o ro /dev/sdX1 /mnt— mount read-onlyumount /mnt/data— unmount; uselsof /mnt/dataorfuser /mnt/dataif "device busy"/etc/fstabformat:UUID=... /mountpoint fstype options dump pass- Use UUIDs (from
blkid) in fstab, not device names — device names can change across reboots - Common mount options:
defaults,noatime,nosuid,noexec,ro mount -a— mount all entries in fstab that aren't already mounted (tests fstab syntax)
XFS filesystems cannot be shrunk — only grown. ext4 can be shrunk (offline only, with
e2fsck first). The exam will present a scenario asking about resizing, and the correct answer depends on the filesystem type.LVM: Logical Volume Manager
LVM Layer Architecture
- PV (Physical Volume) — raw disks or partitions initialized for LVM use
- VG (Volume Group) — pool of storage combining one or more PVs
- LV (Logical Volume) — virtual partitions carved from a VG; flexible and resizable
LVM Commands
pvcreate /dev/sdX— initialize a physical volumevgcreate myvg /dev/sdX— create a volume group;vgextend myvg /dev/sdY— add a PV to VGlvcreate -L 20G -n mylv myvg— create a 20G logical volumelvextend -L +10G /dev/myvg/mylv— increase LV size by 10G- After
lvextendon ext4:resize2fs /dev/myvg/mylvto grow the filesystem - After
lvextendon XFS:xfs_growfs /mountpointto grow the filesystem (XFS grow is online) lvreduce -L -5G /dev/myvg/mylv— decrease LV size (ext4 only, must unmount first)pvs/vgs/lvs— brief display of PV/VG/LV informationpvdisplay/vgdisplay/lvdisplay— detailed outputlvcreate -L 5G -s -n snap /dev/myvg/mylv— create a snapshot of an LV
To shrink an ext4 LV: unmount →
e2fsck -f → resize2fs to new smaller size → lvreduce. XFS cannot be shrunk at all. The exam frequently tests this order-of-operations for both grow and shrink scenarios.💻 Worked scenario — LVM build and online extend
Task: create a 10G XFS volume from two raw disks, mount it persistently, then extend by 5G. Walk: (1) pvcreate /dev/sdb /dev/sdc; (2) vgcreate datavg /dev/sdb /dev/sdc; (3) lvcreate -L 10G -n datalv datavg; (4) mkfs.xfs /dev/datavg/datalv; (5) mkdir /data && mount /dev/datavg/datalv /data; (6) get the UUID with blkid /dev/datavg/datalv, then add to /etc/fstab: UUID=<value> /data xfs defaults 0 0; (7) mount -a to test. To extend: lvextend -r -L +5G /dev/datavg/datalv — the -r flag grows the LV and the XFS filesystem in one step. Confirm with df -h /data showing ~15G total.
RAID with mdadm
RAID Levels
- RAID 0 (striping) — performance, no redundancy; min 2 disks; if one disk fails, all data is lost
- RAID 1 (mirroring) — full redundancy, 50% usable capacity; min 2 disks; can lose N-1 disks
- RAID 5 (distributed parity) — min 3 disks; can lose 1 disk; usable capacity = (N-1) disks
- RAID 6 (double parity) — min 4 disks; can lose 2 disks; usable = (N-2) disks
- RAID 10 (stripe of mirrors) — min 4 disks; high performance + redundancy; can lose 1 disk per mirror set
mdadm Commands
mdadm --create /dev/md0 --level=5 --raid-devices=3 /dev/sd{b,c,d}— create RAID 5cat /proc/mdstat— view RAID status and rebuild progressmdadm --detail /dev/md0— detailed RAID array infomdadm --add /dev/md0 /dev/sde— add a hot spare or replacement drivemdadm --fail /dev/md0 /dev/sdb— mark a drive as failed;mdadm --remove /dev/md0 /dev/sdb— remove it/etc/mdadm.confor/etc/mdadm/mdadm.conf— persist RAID config across reboots
Software RAID with mdadm is flexible and independent of hardware controllers. RAID 5 with 3 disks gives 2 disks of usable space. RAID 6 with 4 disks gives 2 disks of usable space. RAID 10 with 4 disks gives 2 disks of usable space — but RAID 10 is faster and more resilient for databases.
Swap Space Management
Creating and Managing Swap
mkswap /dev/sdX2— format a partition as swap spaceswapon /dev/sdX2— activate swap;swapoff /dev/sdX2— deactivateswapon -s(orswapon --show) — list active swap devices with priority and usage- Persist in
/etc/fstab:UUID=... none swap sw 0 0 - Swap file:
fallocate -l 2G /swapfile→chmod 600 /swapfile→mkswap /swapfile→swapon /swapfile cat /proc/sys/vm/swappiness— view swappiness (default 60); lower values reduce swap aggressivenesssysctl vm.swappiness=10— set swappiness temporarily; persist in/etc/sysctl.d/99-swap.conf
Disk Encryption with LUKS
cryptsetup & LUKS
cryptsetup luksFormat /dev/sdX1— initialize a LUKS encrypted container (destroys data)cryptsetup luksOpen /dev/sdX1 cryptdata— unlock the container; creates/dev/mapper/cryptdatamkfs.ext4 /dev/mapper/cryptdata— create filesystem on the unlocked devicemount /dev/mapper/cryptdata /mnt/secure— mount the encrypted filesystemcryptsetup luksClose cryptdata— lock/close the containercryptsetup luksDump /dev/sdX1— display LUKS header info (slots used, cipher)/etc/crypttab— maps LUKS devices to mapper names for auto-unlock at boot (with keyfile or passphrase prompt)
After adding a LUKS-encrypted device to
/etc/crypttab and /etc/fstab, you must rebuild the initramfs (dracut --force on RHEL) so the initramfs includes the cryptsetup tools needed to unlock the device early in the boot process.Key takeaways
- Provisioning order: partition (
fdisk/gdisk/parted) →mkfs.xfs/mkfs.ext4→ mount +/etc/fstabwith UUID;fdiskonly for ≤2 TB MBR disks,gdisk/partedfor GPT. - LVM =
pvcreate → vgcreate → lvcreate; grow online withlvextend -r; shrink only ext4 (offline, afterresize2fs) — XFS cannot shrink at all. - RAID with mdadm for software arrays (RAID 1 / 5 / 6 / 10 — capacity and resiliency tables matter); LUKS for at-rest encryption (
cryptsetup luksFormat+/etc/crypttab); always rebuild initramfs after a crypt change.
⚡ Mini-quiz — Drill LVM grow/shrink, RAID capacity math, LUKS boot-time unlock, and fstab UUIDs.
Quick quiz →
05
Networking
6 lessons · ~5 hours
Networking
6 lessons · ~5 hours
The Linux+ networking domain expects you to fluently switch between three layers: ephemeral (the
ip suite, lost on reboot), persistent (NetworkManager via nmcli/nmtui or config files), and filter (firewalld, ufw, raw iptables). Module 05 maps each layer to its command set, covers DNS via /etc/resolv.conf + /etc/nsswitch.conf, and walks SSH key-based auth — the most-tested authentication topic on the exam.
The ip Command Suite
Replacing Legacy net-tools
- The
ipcommand (from theiproute2package) replaces deprecated tools:ifconfig,route,arp,netstat ip addr show(orip a) — display IP addresses on all interfacesip addr add 192.168.1.10/24 dev eth0— assign an IP address (non-persistent)ip addr del 192.168.1.10/24 dev eth0— remove an IP addressip link show— display network interface state;ip link set eth0 up/down— bring interface up/downip route show(orip r) — display the routing tableip route add default via 192.168.1.1— add a default gateway (non-persistent)ip route add 10.0.0.0/8 via 192.168.1.254 dev eth0— add a static routeip neigh show— display the ARP/neighbor cache
Changes made with the
ip command are not persistent across reboots. For persistent configuration, use NetworkManager (nmcli) or edit interface config files in /etc/NetworkManager/system-connections/.NetworkManager: nmcli & nmtui
nmcli Commands
nmcli connection show— list all configured network connectionsnmcli connection show --active— list only active connectionsnmcli connection up CONNECTION_NAME— activate a connectionnmcli connection down CONNECTION_NAME— deactivate a connectionnmcli connection modify CONNECTION_NAME ipv4.addresses 192.168.1.50/24— set static IPnmcli connection modify CONNECTION_NAME ipv4.gateway 192.168.1.1— set gatewaynmcli connection modify CONNECTION_NAME ipv4.dns "8.8.8.8 8.8.4.4"— set DNS serversnmcli connection modify CONNECTION_NAME ipv4.method manual— switch from DHCP to staticnmcli device wifi list— list available Wi-Fi networksnmtui— text-based interactive UI for NetworkManager; useful when no GUI is available
Config File Location
- Connection profiles:
/etc/NetworkManager/system-connections/(keyfile format in RHEL 8+) - Restart networking:
nmcli connection reloadthennmcli connection up CONNECTION
💻 Worked scenario — persistent static IP with nmcli
Task: configure ens3 with static IP 10.0.1.50/24, gateway 10.0.1.1, DNS 1.1.1.1, and set hostname to server2.lab.local. Walk: (1) hostnamectl set-hostname server2.lab.local; (2) nmcli con mod ens3 ipv4.addresses 10.0.1.50/24 ipv4.gateway 10.0.1.1 ipv4.dns 1.1.1.1 ipv4.method manual; (3) nmcli con up ens3 to activate — the mod writes to disk but changes are only applied when the connection is brought up; (4) verify: ip a show ens3 (IP assigned), ip route show default (gateway), cat /etc/resolv.conf (DNS), hostname (hostname). Critical: anything set via ip addr add instead of nmcli vanishes at the next reboot.
DNS & Name Resolution
Key Files & Tools
/etc/hosts— static hostname-to-IP mappings; checked before DNS by default/etc/resolv.conf— specifies DNS servers (nameserver 8.8.8.8) and search domains (search example.com)/etc/nsswitch.conf— controls lookup order; thehosts:line (typicallyfiles dns) determines whether/etc/hostsis checked before DNSdig DOMAIN— detailed DNS query;dig @8.8.8.8 DOMAIN— query specific server;dig -x IP— reverse lookupnslookup DOMAIN— simple DNS query (older tool); interactive mode:nslookupthenserver 8.8.8.8host DOMAIN— quick DNS lookup;host IP— reverse DNSsystemd-resolve --status— show DNS configuration used by systemd-resolved
The order of name resolution is controlled by
/etc/nsswitch.conf, not /etc/resolv.conf. If the exam asks how to make /etc/hosts take precedence over DNS, the answer is to check the hosts: line in nsswitch.conf — it must list files before dns.Firewall: iptables, ufw & firewalld
iptables Fundamentals
- Three main chains: INPUT (packets destined for the local system), OUTPUT (packets originating from local system), FORWARD (routed packets)
iptables -L -n -v --line-numbers— list all rules with line numbers and packet countsiptables -A INPUT -p tcp --dport 22 -j ACCEPT— append rule to allow SSHiptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT— insert rule at position 1iptables -D INPUT 3— delete rule by line numberiptables -A INPUT -s 10.0.0.5 -j DROP— drop all traffic from a source IPiptables -P INPUT DROP— set default policy to DROP (deny-all baseline)- Persist:
iptables-save > /etc/iptables/rules.v4; restore:iptables-restore < /etc/iptables/rules.v4
ufw & firewalld
ufw enable— enable the UFW firewall (Ubuntu/Debian);ufw allow 22/tcp— allow SSH;ufw deny 23— block telnetfirewalld— zone-based firewall on RHEL/Fedora;firewall-cmd --list-all— show active zone configfirewall-cmd --permanent --add-service=http— allow HTTP;--reloadapplies permanent changes
iptables rules are evaluated top-to-bottom; the first matching rule wins. This means more specific rules must come before general rules. If you have a DROP rule at position 1 and an ACCEPT for SSH at position 2, SSH will be blocked. Use
--line-numbers and -I (insert) for targeted rule placement.SSH Configuration & Key-Based Auth
Generating & Deploying SSH Keys
ssh-keygen -t ed25519 -C "comment"— generate an Ed25519 key pair (recommended over RSA for new keys)ssh-keygen -t rsa -b 4096— generate 4096-bit RSA key pair- Private key:
~/.ssh/id_ed25519(protect withchmod 600); Public key:~/.ssh/id_ed25519.pub ssh-copy-id user@host— copy public key to remote host's~/.ssh/authorized_keys~/.ssh/authorized_keyson the server: must bechmod 600and owned by the user~/.ssh/directory: must bechmod 700and owned by the user
sshd_config Hardening
PasswordAuthentication no— disable password auth (force key-based only)PermitRootLogin no— prevent direct root login via SSHAllowUsers alice bob— whitelist specific users; all others deniedPort 2222— change SSH port (security through obscurity; adjust firewall accordingly)ClientAliveInterval 300/ClientAliveCountMax 2— disconnect idle sessions after 10 minutes- After editing
/etc/ssh/sshd_config:systemctl restart sshd
Network Troubleshooting
Essential Diagnostic Commands
ping -c 4 HOST— test basic connectivity;ping -I eth0 HOST— send from specific interfacetraceroute HOST— show path packets take (hop-by-hop);tracepath HOST— similar but no root requiredss -tulnp— list listening TCP (t) and UDP (u) sockets with process names; replacesnetstat -tulnptcpdump -i eth0 port 80— capture HTTP traffic;tcpdump -i eth0 -w capture.pcap— write to filetcpdump -i eth0 host 10.0.0.5 and tcp— filter by host and protocolcurl -I https://example.com— fetch HTTP headers only;curl -v URL— verbose output showing TLS handshakewget -O /dev/null URL— test download speed;wget --spider URL— check URL without downloadingnc -zv HOST PORT— test if a TCP port is open (netcat);nc -l 8080— listen on port 8080
ss -tulnp is the modern replacement for netstat -tulnp. The flags: -t TCP, -u UDP, -l listening only, -n show numbers not names, -p show process info. The Linux+ exam may test either command.Key takeaways
- Inspect with
ip a,ip r,ss -tulnp(the modernnetstat); change persistently withnmcli/nmtui—ip-suite changes vanish on reboot. - Resolver order is set by
/etc/nsswitch.conf, NOT/etc/resolv.conf; firewalls follow first-match:firewallduses zones,ufwis the Ubuntu-friendly wrapper,iptablesis the raw kernel layer underneath. - SSH hardening hits in three places:
/etc/ssh/sshd_config(PermitRootLogin no,PasswordAuthentication no),~/.ssh/authorized_keys(key-based auth), andssh-keygen -t ed25519for modern key pairs.
⚡ Mini-quiz — Drill
Quick quiz →
ip vs nmcli, nsswitch order, firewalld zones, and SSH key auth.
06
Security & Hardening
6 lessons · ~5 hours
Security & Hardening
6 lessons · ~5 hours
Security on Linux+ splits into Mandatory Access Control (SELinux on RHEL family, AppArmor on Debian/Ubuntu/SUSE), cryptography (GPG signing + encryption), and hardening (least privilege, audit, log integrity). The exam loves to compare the two MAC systems — label-based SELinux contexts vs path-based AppArmor profiles — and to test
audit2allow/audit2why when something denies. Module 06 covers all three areas with the production patterns.
SELinux
SELinux Modes & Status
- Enforcing — SELinux policy is enforced; violations are blocked and logged
- Permissive — violations are logged but NOT blocked; useful for troubleshooting and policy development
- Disabled — SELinux is completely turned off; requires reboot + relabeling to re-enable
getenforce— display current mode (Enforcing/Permissive/Disabled)setenforce 0— switch to Permissive (temporary, survives only until reboot)setenforce 1— switch to Enforcing (temporary)- Persistent mode: edit
/etc/selinux/config→ setSELINUX=enforcing/permissive/disabled
File Context Management
ls -Z /var/www/html/— show SELinux file context labelsrestorecon -Rv /var/www/html/— restore default SELinux contexts recursively (fixes "wrong context" denials)chcon -t httpd_sys_content_t /new/file— change file context temporarily (overridden by restorecon)semanage fcontext -a -t httpd_sys_content_t "/newpath(/.*)?"— add a persistent context rulerestorecon -Rv /newpath— apply the newly added context rulegetsebool -a | grep httpd— list all SELinux booleans related to httpdsetsebool -P httpd_can_network_connect on— enable a boolean persistently (-P)
Analyzing Denials
audit2why < /var/log/audit/audit.log— explain why actions were deniedaudit2allow -M mypolicy < /var/log/audit/audit.log— generate a custom allow policy module from denialssemodule -i mypolicy.pp— install a custom SELinux policy module
After using
chcon to change a file context, the change is temporary. A subsequent restorecon will reset it back to the default policy label. The correct permanent approach is semanage fcontext followed by restorecon. The exam tests this two-step workflow.💻 Worked scenario — SELinux deny-and-fix for nginx
Symptom: nginx returns 403 on files in /data/web/ even though the Unix permissions are correct. Walk: (1) getenforce → Enforcing; (2) grep AVC /var/log/audit/audit.log | tail -5 → shows a denial for httpd_t trying to read /data/web; (3) audit2why < /var/log/audit/audit.log explains the cause: wrong SELinux file context; (4) fix permanently: semanage fcontext -a -t httpd_sys_content_t "/data/web(/.*)?"; (5) restorecon -Rv /data/web/ applies the rule; (6) reload nginx and confirm the 403 is gone. If you had used chcon -t httpd_sys_content_t /data/web instead, the next restorecon run would silently revert it — permanent fix requires semanage fcontext.
AppArmor
AppArmor Overview & Status
- AppArmor is the MAC (Mandatory Access Control) framework used on Debian/Ubuntu systems (vs SELinux on RHEL)
aa-status— show AppArmor status: profiles loaded, enforcement mode per profile- Profile modes: enforce (blocks violations), complain (logs but does not block — like SELinux permissive)
aa-enforce /etc/apparmor.d/usr.sbin.nginx— put a profile into enforce modeaa-complain /etc/apparmor.d/usr.sbin.nginx— put into complain (logging) mode- Profile files live in:
/etc/apparmor.d/ apparmor_parser -r /etc/apparmor.d/PROFILE— reload a profile after editingaa-genprof /path/to/binary— generate a new profile interactively by watching program behavior
AppArmor profiles are path-based (they restrict what files a program can access by pathname). SELinux is label-based (it uses extended attribute labels on files and processes). The Linux+ exam may ask which system uses which approach.
GPG Encryption & Signing
GPG Key Management
gpg --gen-key— generate a new GPG key pair interactivelygpg --list-keys— list all keys in the public keyringgpg --export -a "User Name" > public.key— export public key to ASCII-armored filegpg --import public.key— import a public key from a filegpg --keyserver keyserver.ubuntu.com --recv-keys KEY_ID— download a key from a keyserver
Encryption, Signing & Verification
gpg --encrypt -r "Recipient" file— encrypt file for recipient (producesfile.gpg)gpg --decrypt file.gpg > file— decrypt a filegpg --sign file— create a signed version of a file (embedded signature)gpg --detach-sign file— create a separatefile.sigsignature filegpg --verify file.sig file— verify a detached signature- RPM uses GPG to sign packages —
rpm -K package.rpmverifies the package signature
System Hardening
PAM-Based Controls
/etc/pam.d/— service-specific PAM configuration;system-authandpassword-authare key files on RHELpam_pwquality.so— enforces password complexity rules configured in/etc/security/pwquality.conffaillock— PAM module that locks accounts after N failed login attempts; check withfaillock --user USERNAME; reset withfaillock --user USERNAME --reset/etc/security/limits.conf— set per-user/group resource limits:nofile(open files),nproc(processes),memlock(locked memory)ulimit -n— show current shell's open file descriptor limit;ulimit -n 65536— set for current session
sudoers Configuration
- Always edit sudoers with
visudo— validates syntax before saving, preventing lockouts - Format:
USER HOST=(RUNAS) COMMANDS— e.g.,alice ALL=(ALL) ALL - Group syntax:
%admins ALL=(ALL) ALL - NOPASSWD:
bob ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx - Restrict to specific commands:
carol ALL=(root) /usr/bin/dnf install, /usr/bin/dnf remove - Include drop-in files:
/etc/sudoers.d/— add separate files here rather than editing/etc/sudoersdirectly
Log Security & Auditing
Key Log Files
/var/log/auth.log(Debian) or/var/log/secure(RHEL) — authentication events: logins, sudo usage, SSH attempts/var/log/messages(RHEL) or/var/log/syslog(Debian) — general system messagesjournalctl -u sshd --since "1 hour ago"— filter systemd journal by unit and timejournalctl _COMM=sshd— all journal entries from the sshd processjournalctl -p err— show only error-level messageslastb— list bad (failed) login attempts from/var/log/btmplast— list successful logins from/var/log/wtmpwho/w— currently logged-in users
auditd
auditd— the Linux audit daemon; writes security events to/var/log/audit/audit.logauditctl -w /etc/passwd -p wa -k passwd_changes— watch /etc/passwd for write and attribute changesausearch -k passwd_changes— search audit log by keyausearch -ua USERNAME— search audit events by useraureport --summary— summary of audit events by category- Persistent rules:
/etc/audit/rules.d/audit.rules
audit2allow generates allow rules from denial messages but always review the output — it may create overly permissive rules. Use the minimum necessary permissions and apply the principle of least privilege. The exam may test whether you know audit2why (explains denials) vs audit2allow (generates allow policy).Key takeaways
- SELinux = label-based; modes are
enforcing/permissive/disabled;chconis temporary,semanage fcontext+restoreconis permanent; troubleshoot withausearch+audit2why/audit2allow. - AppArmor = path-based profiles in
/etc/apparmor.d/, modes areenforceandcomplain; manage withaa-enforce,aa-complain,aa-status. - Hardening = principle of least privilege everywhere — disable unused services (
systemctl mask), tightensshd_config, sign packages with GPG, and audit withauditd+ journalctl filters; correlate failed logins vialastband/var/log/secure.
⚡ Mini-quiz — Drill SELinux contexts, AppArmor modes, GPG signing, and auditd rules.
Quick quiz →
07
Scripting, Containers & Troubleshooting
5 lessons · ~7 hours
Scripting, Containers & Troubleshooting
5 lessons · ~7 hours
The final domain bundles the day-to-day muscle memory: bash automation (variables, conditionals, loops, return codes), text processing (
grep/sed/awk pipelines), scheduling (cron, anacron, systemd timers), containers (Docker vs Podman, the daemonless distinction the exam loves), configuration management (Ansible, agentless, idempotent), and troubleshooting (the systematic flow: status → logs → kernel → resources). Module 07 walks each in production order.
Bash Scripting Fundamentals
Script Structure & Variables
- Always start with a shebang:
#!/bin/bash(or#!/usr/bin/env bashfor portability) - Make executable:
chmod +x script.sh; run with./script.shorbash script.sh - Variables:
NAME="Alice"(no spaces around=); reference with$NAMEor${NAME} - Command substitution:
DATE=$(date +%Y-%m-%d)— stores command output in variable - Special variables:
$?(exit code of last command),$#(number of arguments),$@(all arguments as separate strings),$0(script name),$1-$9(positional arguments)
Control Flow
- If/elif/else:
if [ "$VAR" = "value" ]; then ... elif [ condition ]; then ... else ... fi - For loop:
for FILE in /etc/*.conf; do echo "$FILE"; done - While loop:
while [ $COUNT -lt 10 ]; do ((COUNT++)); done - Until loop:
until ping -c1 HOST >/dev/null 2>&1; do sleep 5; done - Functions:
function check_service() { systemctl is-active "$1" || return 1; }
test Operators
- File tests:
-f(regular file),-d(directory),-e(exists),-r(readable),-w(writable),-x(executable),-s(non-empty) - String tests:
-z(zero length / empty),-n(non-zero length / not empty),=(equal),!=(not equal) - Integer comparison:
-eq,-ne,-lt,-le,-gt,-ge
$? must be checked immediately after the command it refers to — the very next command overwrites it. A common pattern: command; RC=$?; if [ $RC -ne 0 ]; then .... Also: set -e at the top of a script causes it to exit immediately on any non-zero return code.💻 Worked scenario — service health-check script
Task: write a script that checks if nginx and sshd are running, starts any that aren't, and logs results. Walk: Start with #!/bin/bash and set -e removed (we want the loop to continue on failure). Declare an array: SERVICES=(nginx sshd). Loop: for SVC in "${SERVICES[@]}"; do — always quote array expansions. Check status: if ! systemctl is-active --quiet "$SVC"; then — is-active --quiet exits 0 (active) or non-zero (not), so ! triggers on failure. Inside: systemctl start "$SVC" && echo "$(date '+%Y-%m-%d %T'): started $SVC" >> /var/log/svc-check.log. Close with fi; done. Schedule via cron: add */5 * * * * root /usr/local/bin/svc-check.sh to /etc/cron.d/svc-check.
Text Processing Toolkit
Core Text Processing Commands
grep -E "pattern" file— extended regex search;-icase-insensitive;-rrecursive;-vinvert match;-lfilenames only;-ccount matchesgrep -P "\d{3}-\d{4}" file— Perl-compatible regex for complex patternssed 's/old/new/g' file— substitute all occurrences;-iflag edits file in-place;sed -n '5,10p' file— print lines 5–10awk '{print $1, $3}' file— print fields 1 and 3;awk -F: '{print $1}' /etc/passwd— use colon as delimiterawk '$3 > 1000 {print $1}' /etc/passwd— conditional: print username if UID > 1000cut -d: -f1,3 /etc/passwd— cut fields 1 and 3 from colon-delimited filesort -k3 -n file— sort numerically by field 3;sort -rreverse order;sort -uunique linesuniq -c— count duplicate consecutive lines; always pipe throughsortfirsttr 'a-z' 'A-Z'— translate lowercase to uppercase;tr -d '\r'— remove carriage returnswc -l file— count lines;wc -wwords;wc -cbyteshead -n 20 file— first 20 lines;tail -n 20 file— last 20 lines;tail -f /var/log/syslog— follow a file live
Combining text processing tools with pipes is a core Linux skill. A common exam pattern:
cat /etc/passwd | awk -F: '$3 >= 1000 {print $1}' | sort — list all regular users sorted alphabetically. Know how to chain grep | awk | sort | uniq pipelines.Containers: Docker & Podman
Core Container Commands
docker run -d -p 8080:80 --name webserver nginx— run nginx in background, map port 8080→80docker ps— list running containers;docker ps -a— all containers including stoppeddocker images— list local imagesdocker pull IMAGE:TAG— pull an image from registrydocker exec -it CONTAINER bash— interactive shell in a running containerdocker logs CONTAINER— view container logs;docker logs -f CONTAINER— followdocker stop CONTAINER— gracefully stop;docker rm CONTAINER— remove stopped containerdocker rmi IMAGE— remove an imagedocker run -v /host/path:/container/path IMAGE— bind mount a host directory into a containerpodman— drop-in Docker replacement; rootless and daemonless by design; commands are identical to Docker in most cases
Writing a Dockerfile
FROM ubuntu:22.04— base imageRUN apt-get update && apt-get install -y nginx— execute commands during image buildCOPY ./app /var/www/html/— copy files from build context into imageENV APP_ENV=production— set environment variableEXPOSE 80— document which port the container listens on (does not publish)CMD ["nginx", "-g", "daemon off;"]— default command to run (can be overridden)ENTRYPOINT ["/entrypoint.sh"]— executable that always runs (CMD becomes its arguments)docker build -t myapp:1.0 .— build image from Dockerfile in current directory
Podman is daemonless — it does not require a background daemon process. This makes rootless containers possible (regular users can run containers without
sudo). Docker requires the docker daemon running as root. The Linux+ exam specifically tests this architectural difference.Ansible Automation
Inventory & Ad-Hoc Commands
- Inventory file (
/etc/ansible/hostsor custom file with-i): groups of hosts in INI or YAML format ansible all -m ping— test connectivity to all hosts in inventoryansible webservers -m shell -a "df -h"— run shell command on webservers groupansible all -m copy -a "src=/etc/hosts dest=/tmp/hosts"— copy file to all hostsansible all -m service -a "name=nginx state=started"— ensure nginx is runningansible all -b -m dnf -a "name=httpd state=present"— install httpd (become=sudo)
Playbook Structure
- Playbooks are YAML files defining plays (which hosts to target) and tasks (what to do)
- Key modules:
apt/dnf(package management),copy(copy files),template(Jinja2 templates),service(manage services),user(manage users),file(manage file permissions/ownership) ansible-playbook site.yml— run a playbookansible-playbook site.yml --check— dry run (shows what would change without changing it)ansible-playbook site.yml -v/-vvv— verbose output for debuggingansible-playbook site.yml --limit webservers— run only against a specific group
Ansible is agentless — it uses SSH to connect to managed nodes. No agent software is needed on managed hosts. Only Python must be installed on the target. Ansible is idempotent by design: running a playbook multiple times produces the same result.
Troubleshooting Workflow
Systematic Troubleshooting Steps
- Step 1 — Service status:
systemctl status servicename— shows active/failed state, last 10 log lines, and exit code - Step 2 — Journal:
journalctl -xe -u servicename— full journal with explanations;journalctl --boot -1— previous boot logs - Step 3 — Kernel messages:
dmesg | tail -50— recent kernel messages;dmesg | grep -i error - Step 4 — Resources: check disk (
df -h,du -sh /*), memory (free -h), CPU (top,vmstat 1 5), I/O (iostat -x 1 5) - Step 5 — OOM killer:
dmesg | grep -i "out of memory"orgrep -i oom /var/log/kern.log— identifies memory-killed processes
Common Failure Scenarios
- Service fails to start: check
systemctl statusandjournalctl -xefor the exact error; often a config file syntax error or missing dependency - Disk full:
df -hto identify full filesystem;du -sh /var/log/*to find large log files;journalctl --vacuum-size=500Mto trim journal - High CPU:
topsorted by CPU (Pkey);ps aux --sort=-%cpu | head - High memory / swap usage:
free -h;vmstat 1to watch memory pressure; consider increasing swap or identifying memory leaks withps aux --sort=-%mem - Cannot SSH to host: check firewall (
iptables -Lorfirewall-cmd --list-all), sshd status, SELinux (getenforce),ss -tlnp | grep 22
The Linux+ exam includes scenario-based troubleshooting questions. Always follow the systematic flow: status → logs → kernel → resources. The OOM (Out Of Memory) killer is a specific Linux kernel feature that kills processes to free memory under extreme memory pressure — look for it in
dmesg or /var/log/kern.log, not just /var/log/messages.Key takeaways
- Bash scripts use shebang
#!/bin/bash, exit codes from$?, andset -efor fail-fast;grep/sed/awkchained through pipes (awk -F:,sed -i 's///') cover most parsing scenarios. - Schedule with
cron(* * * * *minute / hour / dom / month / dow),anacronfor irregular runs, and systemd timers (the modern alternative — atomic with their service units). Persistent rules live in/etc/crontaband/etc/cron.d/. - Podman is daemonless and rootless-capable — the key architectural difference from Docker the exam tests. Ansible is agentless (SSH + Python on target) and idempotent. Troubleshoot in the order
systemctl status→journalctl -xe→dmesg→top/free/ss.
⚡ Mini-quiz — Drill bash conditionals, cron syntax, Podman vs Docker, and the troubleshooting flow.
Quick quiz →