Up to now srv-tramontana has always booted. You have installed, configured, hardened and defended a system starting from the premise that, when you switch it on, a prompt appears. This lesson breaks that premise, and it does so in both directions: first you will understand exactly what happens between pressing the button and seeing the prompt, and then you will learn to intervene when that chain breaks.
It is the skill that separates the people who reinstall from the people who fix. An fstab with the wrong UUID, an initramfs that does not include the LUKS module, a GRUB overwritten by another operating system, a lost root password: they are all five-minute problems if you know where to intervene, and an eight-hour reinstall if you do not. And since Module 5 taught you to modify fstab and Module 6 to encrypt a volume with LUKS, you already have on the machine exactly the ingredients that cause these failures.
A note about the lab. Several of this lesson's procedures require the VM console, not an SSH session: when the system does not boot, there is no network. Be clear about how to open the VirtualBox console before you start, and take a fresh snapshot (06-before-boot) — you are going to break the boot process on purpose.
Contents
- The complete boot chain
- The firmware: UEFI and BIOS
- GRUB 2: the boot loader
- The initramfs: the minimal intermediate system
- The kernel and handing control to PID 1
- systemd and targets
- Kernel command-line parameters
- Recovery: intervening in the boot process
- Recovering a system that will not boot
- Reinstalling GRUB from rescue media
The complete boot chain
Booting a system is a succession of programs, each with more capability than the last, in which every link loads the next one and hands over control. That is precisely why it is called bootstrapping.
graph TD
A["UEFI firmware<br/>(on the board)"] -->|reads the ESP| B["GRUB 2<br/>shimx64.efi → grubx64.efi"]
B -->|loads into RAM| C["vmlinuz<br/>(compressed kernel)"]
B -->|loads into RAM| D["initrd.img<br/>(initramfs)"]
C -->|decompresses<br/>and initialises| E["Kernel<br/>drivers, memory, scheduler"]
D -->|temporary root| E
E -->|mounts the real root<br/>and does switch_root| F["systemd<br/>PID 1"]
F -->|activates dependencies| G["default.target<br/>= multi-user.target"]
G --> H["getty, sshd,<br/>tramontana.service"]
The five links and their responsibilities, worth keeping in your head because diagnosis consists of identifying which one broke:
| Link | What it does | How you know it got this far |
|---|---|---|
| Firmware | Initialises the hardware, finds the boot loader | The board's logo or the BIOS screen appears |
| GRUB | Finds the kernel, loads it into memory, passes it parameters | The menu appears (or the screen stays black with GRUB in rescue mode) |
| Kernel | Initialises the hardware for real, mounts the root | The dmesg messages start scrolling on screen |
| initramfs | Supplies the drivers and utilities needed to mount the root | A failure here gives you the (initramfs) prompt |
| systemd | Starts the services in the right order | The [ OK ] Started ... lines appear |
That table is the most useful diagnostic tool in the lesson: when somebody tells you "the server will not boot", the first question is how far did it get.
The firmware: UEFI and BIOS
The firmware lives on the motherboard, runs before anything that is on the disk, and its job is to leave the hardware in a usable state and locate something to boot. There are two generations, and srv-tramontana uses the modern one:
| BIOS + MBR | UEFI + GPT | |
|---|---|---|
| Age | Since 1981 | Since 2005, universal since 2012 |
| Where it looks for the boot code | The first 446 bytes of the disk (MBR) | .efi files on the ESP partition |
| Size of the initial loader | 446 bytes: it forces a two-stage boot | A complete executable, with no practical limit |
| Partition table | MBR: 4 primaries, 2 TiB maximum | GPT: 128 partitions, 8 ZiB |
| Filesystems it understands | None | FAT32 |
| Secure boot | No | Secure Boot: cryptographic signature of the loader |
| Managing entries | There is none | NVRAM variables, manageable with efibootmgr |
The key difference is the third row. Under BIOS, the loader had to fit in 446 bytes, which forced a two-stage jump and putting code in the space between the MBR and the first partition. Under UEFI, the firmware can read FAT32, so the loader is an ordinary file on an ordinary partition.
That partition is the ESP (EFI System Partition):
$ lsblk -f /dev/sda
NAME FSTYPE FSVER LABEL UUID MOUNTPOINTS
sda
├─sda1 vfat FAT32 A1B2-C3D4 /boot/efi
├─sda2 ext4 1.0 7c4e1f92-3a8b-4d15-9e26-8f3a0b7c1d54 /boot
└─sda3 ext4 1.0 3f8a2c19-6b4d-4e71-a835-1c9e5f2d0a87 /
$ ls /boot/efi/EFI/
BOOT ubuntu
$ ls -l /boot/efi/EFI/ubuntu/
-rwx------ 1 root root 126976 Aug 18 09:14 grubx64.efi
-rwx------ 1 root root 108 Aug 18 09:14 grub.cfg
-rwx------ 1 root root 955512 Aug 18 09:14 shimx64.efi
-rwx------ 1 root root 1224264 Aug 18 09:14 mmx64.efiThree files worth telling apart, because the order in which they are called matters when something fails:
shimx64.efiis the first link when Secure Boot is active: it is signed by Microsoft (whose key comes preloaded on the boards), and its only function is to verify and load the next one. It is the bridge between the manufacturer's chain of trust and the distribution's.grubx64.efiis GRUB proper, signed by Canonical.mmx64.efi(MokManager) manages your own keys, and it is what makes it possible to sign a kernel module of your own (relevant with DKMS, which you will see in 07-03).
The boot entries are not on the disk but in the board's NVRAM, and they are managed with efibootmgr:
$ sudo efibootmgr -v
BootCurrent: 0000
Timeout: 3 seconds
BootOrder: 0000,0001
Boot0000* ubuntu HD(1,GPT,a1b2c3d4-...,0x800,0x100000)/File(\EFI\ubuntu\shimx64.efi)
Boot0001* UEFI VBOX HARDDISK PciRoot(0x0)/Pci(0x1,0x1)/Ata(0,0,0)BootOrder is the order in which the firmware tries the entries. Being able to reorder it or create a new entry from the running system is what saves the situation when another operating system, or a firmware update, has pushed your entry to the end or deleted it:
# Create a new entry pointing at Ubuntu's loader
$ sudo efibootmgr -c -d /dev/sda -p 1 -L "Ubuntu Tramontana" -l '\EFI\ubuntu\shimx64.efi'
# Put that entry first
$ sudo efibootmgr -o 0002,0000,0001A genuine warning: efibootmgr writes to the board's NVRAM, and on some machines — consumer laptops above all — incorrect use has been known to leave the board unusable. On a VM it is completely harmless, and that is where you should practise.
GRUB 2: the boot loader
GRUB (GRand Unified Bootloader) solves a problem the firmware cannot: knowing how to read Linux filesystems, understanding LVM and RAID, presenting a menu, and loading a kernel with the right parameters.
The files, and the one you never edit
$ head -6 /boot/grub/grub.cfg
#
# DO NOT EDIT THIS FILE
#
# It is automatically generated by grub-mkconfig using templates
# from /etc/grub.d and settings from /etc/default/grub
#The warning is literal and should be taken that way: grub.cfg is generated, and any manual change disappears at the next kernel update, which runs update-grub as part of its maintainer script. The two real sources are:
/etc/default/grub: the settings in key-value format./etc/grub.d/: the scripts that generate each section of the menu.
$ cat /etc/default/grub
GRUB_DEFAULT=0
GRUB_TIMEOUT_STYLE=menu
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT=""
GRUB_CMDLINE_LINUX=""
GRUB_DISABLE_OS_PROBER=falseThe directives you really do touch on a server:
| Directive | What it does | A sensible value on a server |
|---|---|---|
GRUB_TIMEOUT |
Seconds to wait at the menu | 5: enough to intervene, not so much as to be a nuisance |
GRUB_TIMEOUT_STYLE |
menu, hidden or countdown |
menu: hidden is no use if you cannot see it to intervene |
GRUB_DEFAULT |
The default entry | 0, or saved with GRUB_SAVEDEFAULT=true |
GRUB_CMDLINE_LINUX_DEFAULT |
Kernel parameters on a normal boot | See the parameters section |
GRUB_CMDLINE_LINUX |
Parameters on every entry, recovery included | Only what is strictly necessary |
GRUB_DISABLE_RECOVERY |
Hides the recovery entries | false: they are the ones that save you |
GRUB_ENABLE_BLSCFG |
BootLoaderSpec format (RHEL) | Does not apply on Ubuntu |
And the operating rule, following the course's convention:
$ sudo cp -p /etc/default/grub /etc/default/grub.bak-$(date +%F)
$ sudo sed -i 's/^GRUB_TIMEOUT=5$/GRUB_TIMEOUT=10/' /etc/default/grub
$ sudo diff -u /etc/default/grub.bak-$(date +%F) /etc/default/grub
--- /etc/default/grub.bak-2026-08-18
+++ /etc/default/grub
@@ -3,7 +3,7 @@
-GRUB_TIMEOUT=5
+GRUB_TIMEOUT=10
$ sudo update-grub
Sourcing file `/etc/default/grub'
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-6.8.0-41-generic
Found initrd image: /boot/initrd.img-6.8.0-41-generic
Found linux image: /boot/vmlinuz-6.8.0-39-generic
Found initrd image: /boot/initrd.img-6.8.0-39-generic
doneNotice that it finds two kernels. That is not accidental and it is an important safety net: if a kernel update breaks something — a driver that disappears, an incompatible third-party module — the GRUB menu offers you the previous one. The configuration that guarantees it:
$ apt-mark showmanual | grep -c linux-generic
1
$ ls /boot/vmlinuz-*
/boot/vmlinuz-6.8.0-39-generic /boot/vmlinuz-6.8.0-41-genericUbuntu keeps the necessary kernels by default and apt autoremove cleans out the old ones. The mistake to avoid is deleting them by hand to free space in /boot when it fills up: if you are left with only one and that one fails, there is nowhere to go back to. The correct solution when /boot fills up is sudo apt autoremove --purge, which respects the running kernel and the previous one.
The structure of the menu
The scripts run in numerical order and each contributes its part to grub.cfg. 10_linux generates the entries for the installed kernels, 30_os-prober detects other operating systems, and 40_custom is where you put your own entries — because it is the only one that is not regenerated.
To inspect the current menu without rebooting:
$ awk -F"'" '/^menuentry / {print NR": "$2}' /boot/grub/grub.cfg
6: Ubuntu
$ awk -F"'" '/^\s*menuentry / {print " - "$2}' /boot/grub/grub.cfg
- Ubuntu, with Linux 6.8.0-41-generic
- Ubuntu, with Linux 6.8.0-41-generic (recovery mode)
- Ubuntu, with Linux 6.8.0-39-generic
- Ubuntu, with Linux 6.8.0-39-generic (recovery mode)The initramfs: the minimal intermediate system
This is the least understood link and the one that causes the most problems. The problem it solves is a vicious circle:
To mount the root filesystem, the kernel needs the disk controller's driver, the filesystem module, and — on
srv-tramontana— the LVM and LUKS modules, plus thelvmandcryptsetuputilities. But all of that is inside the root filesystem it cannot mount yet.
The initramfs breaks the circle: it is a compressed archive containing a minimal filesystem that GRUB loads into memory alongside the kernel. The kernel mounts it as a temporary root, runs its boot script, which loads the modules, unlocks LUKS, activates the LVM volumes and mounts the real root; and then it does switch_root to move over to it and run the real systemd.
$ ls -lh /boot/initrd.img-*
-rw-r--r-- 1 root root 74M Aug 18 09:14 /boot/initrd.img-6.8.0-41-generic
-rw-r--r-- 1 root root 74M Jul 22 11:02 /boot/initrd.img-6.8.0-39-generic
# What is inside: cryptsetup and lvm are the ones that matter here
$ lsinitramfs /boot/initrd.img-6.8.0-41-generic | grep -E 'cryptsetup$|/lvm$|sd_mod|ext4'
usr/lib/x86_64-linux-gnu/libcryptsetup.so.12
usr/sbin/cryptsetup
usr/sbin/lvm
usr/lib/modules/6.8.0-41-generic/kernel/drivers/scsi/sd_mod.ko.zst
usr/lib/modules/6.8.0-41-generic/kernel/fs/ext4/ext4.ko.zst
$ lsinitramfs /boot/initrd.img-6.8.0-41-generic | wc -l
4127cryptsetup and lvm being there is not automatic: the initramfs-tools scripts include them because they read /etc/crypttab and /etc/fstab at the moment the initramfs is generated. And from that comes the most important operating rule in this section:
After touching
/etc/crypttab, the LVM configuration or the boot disk layout, you must regenerate the initramfs. If you do not, the system will boot with an initramfs that knows nothing about the change and will end up at the(initramfs)prompt.
$ sudo update-initramfs -u # the current kernel
$ sudo update-initramfs -u -k all # every installed kernel
update-initramfs: Generating /boot/initrd.img-6.8.0-41-generic
update-initramfs: Generating /boot/initrd.img-6.8.0-39-genericThe -k all is the one that saves you: if you only regenerate the current one and later need to boot with the previous one, you meet the same failure from the other kernel.
The configuration lives in /etc/initramfs-tools/:
$ grep -v '^#' /etc/initramfs-tools/initramfs.conf | grep -v '^$'
MODULES=most
BUSYBOX=auto
COMPRESS=zstd
DEVICE=
NFSROOT=auto
RUNSIZE=10%MODULES=most includes a broad selection of drivers; MODULES=dep includes only those the current machine needs, and produces a much smaller initramfs — at the price of it no longer booting if you move the disk to different hardware. On a stable virtual server it can make sense; as a default value, most is the prudent choice.
The kernel and handing control to PID 1
When GRUB loads vmlinuz, it decompresses itself and takes control of the hardware for real: it detects CPU and memory, initialises the scheduler, mounts /proc and /sys, loads the built-in drivers and runs the initramfs.
The parameters it was booted with are recorded and can be inspected:
$ cat /proc/cmdline
BOOT_IMAGE=/vmlinuz-6.8.0-41-generic root=UUID=3f8a2c19-6b4d-4e71-a835-1c9e5f2d0a87 ro quiet splashThat file is the first thing to look at when the boot behaves unexpectedly: it says what it actually booted with, not what you think it booted with. A single, a nomodeset or an init= forgotten in GRUB_CMDLINE_LINUX shows up here.
And dmesg is the kernel's diary during the boot:
$ sudo dmesg | head -3
[ 0.000000] Linux version 6.8.0-41-generic (buildd@lcy02-amd64-045) ...
[ 0.000000] Command line: BOOT_IMAGE=/vmlinuz-6.8.0-41-generic root=UUID=3f8a...
[ 0.000000] KERNEL supported cpus: Intel AMD Hygon Centaur zhaoxin
# Errors and warnings from the current boot
$ sudo journalctl -k -b -p warning --no-pager | head -5
# And from the PREVIOUS boot: what you need when the system went down and came back
$ sudo journalctl -k -b -1 -p err --no-pagerBeing able to consult the previous boot is exactly why you made the journal persistent in 05-06. Without /var/log/journal, -b -1 does not exist and the diagnosis of a failed boot is lost when you reboot.
At the end of its initialisation, the kernel runs the init process — today /sbin/init, which is a link to systemd — and hands it control as PID 1. From that moment on the kernel only services system calls; the boot is directed from user space.
systemd and targets
You have known systemd since 05-05: units, dependencies, timers. What this lesson adds is its role as the director of the boot.
systemd activates default.target and, working backwards, everything it needs:
$ systemctl get-default
multi-user.target
$ systemctl list-dependencies default.target | head -12
default.target
● ├─tramontana.service
● ├─cron.service
● ├─fail2ban.service
● ├─ssh.service
● ├─basic.target
● │ ├─sysinit.target
● │ │ ├─systemd-journald.service
● │ │ ├─cryptsetup.target
● │ │ └─local-fs.target
● │ └─sockets.target
● └─timers.targetThe targets you need to know, because they are the ones used in recovery:
| Target | What it activates | What it is for |
|---|---|---|
emergency.target |
A shell only; the root mounted read-only, no /usr |
The last resort; a broken fstab |
rescue.target |
A shell + local filesystems mounted | Fixing most problems |
multi-user.target |
Everything, with no graphical environment | A server's normal state |
graphical.target |
multi-user + a session manager |
A desktop |
And the two boot analysis tools:
$ systemd-analyze
Startup finished in 3.412s (kernel) + 8.847s (userspace) = 12.259s
multi-user.target reached after 8.712s in userspace.
$ systemd-analyze blame | head -6
4.218s [email protected]
2.104s snapd.service
1.882s cryptsetup@backups\x2dencrypted.service
947ms tramontana.service
612ms systemd-udev-settle.service
388ms fail2ban.service
$ systemd-analyze critical-chain
multi-user.target @8.712s
└─tramontana.service @7.765s +947ms
└─postgresql.service @7.762s
└─network-online.target @3.541s
└─systemd-networkd-wait-online.service @1.104s +2.437sThe difference between the two is conceptual and it decides where to optimise: blame sorts by how long each unit took, and critical-chain shows the dependency chain that determines the total time. snapd.service takes 2 seconds, but it is not in the critical chain: it starts in parallel and delays nothing. systemd-networkd-wait-online, on the other hand, is, and there it really is worth investigating.
Kernel command-line parameters
The parameters GRUB passes to the kernel are the lever for intervening in the boot. The ones you need to know:
| Parameter | Effect | When it is used |
|---|---|---|
ro / rw |
Mounts the root read-only / read-write | rw with init=/bin/bash |
quiet |
Silences the kernel messages | Remove it to see where it fails |
splash |
The graphical boot screen | Remove it for the same reason |
single or 1 |
Boots into rescue.target |
Maintenance mode |
systemd.unit=<target> |
Boots into the given target | emergency.target, rescue.target |
init=/bin/bash |
Replaces PID 1 with a shell | A lost root password; systemd does not start |
systemd.mask=<unit> |
Masks a unit for this boot only | A service that hangs the boot |
nomodeset |
Disables the kernel's graphics drivers | A black screen caused by video |
noapic / acpi=off |
Disables interrupt / power management | Firmware-induced lock-ups |
emergency |
Equivalent to systemd.unit=emergency.target |
The last resort |
debug systemd.log_level=debug |
Exhaustive logging | Fine-grained boot diagnosis |
The first practical recovery tip is the simplest: remove quiet splash. The pretty boot screen hides precisely the messages that would tell you where it broke.
Recovery: intervening in the boot process
Editing the menu entry
In the GRUB menu, with the entry selected, the e key opens the editor. It is an ephemeral editor: the changes affect this boot only and touch nothing on the disk. That property is what makes it safe to experiment with.
The procedure:
- Power on the VM and, if the menu does not appear, hold down
Shift(BIOS) or pressEscrepeatedly (UEFI). - Select the Ubuntu entry and press
e. - Find the line that starts with
linux /vmlinuz-.... - Modify whatever you need at the end of that line.
Ctrl+XorF10to boot with those parameters.
The original line and the three most useful variants:
# Original linux /vmlinuz-6.8.0-41-generic root=UUID=3f8a2c19-... ro quiet splash # See what is really going on linux /vmlinuz-6.8.0-41-generic root=UUID=3f8a2c19-... ro # Boot into rescue mode (root shell, filesystems mounted) linux /vmlinuz-6.8.0-41-generic root=UUID=3f8a2c19-... ro systemd.unit=rescue.target # Skip systemd entirely: a shell as PID 1 linux /vmlinuz-6.8.0-41-generic root=UUID=3f8a2c19-... rw init=/bin/bash
rescue versus emergency
rescue.target |
emergency.target |
|
|---|---|---|
| Local filesystems | Mounted (local-fs.target) |
The root only, read-only |
/usr, /var on separate partitions |
Mounted | Not mounted |
| Services | None beyond the basics | None |
| Network | No | No |
| Requires the root password | Yes | Yes |
| When to use it | Nearly always | When rescue will not start either |
rescue is the one used 90% of the time: you have the filesystems mounted and the tools available. emergency is for when the problem is in the mounting itself — a broken fstab is the typical case — and there the first thing to do is make the root writable:
# In emergency.target the root is read-only
root@srv-tramontana:~# mount -o remount,rw /
root@srv-tramontana:~# nano /etc/fstabinit=/bin/bash and the read-only root
init=/bin/bash is the most powerful resource: it replaces PID 1 with a shell, so systemd never runs at all. It is useful when the problem is in systemd or in authentication itself.
And it has two peculiarities that are disconcerting the first time:
PATH is not set, because no startup script has run. You fix it by hand:
bash-5.2# export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
bash-5.2# mount | head -1
/dev/mapper/... on / type ext4 (ro,relatime)And the root is read-only, because the ro parameter is still in force and nobody has remounted it:
When you finish, and this is important: do not reboot with reboot, because there is no systemd to service the request and data may be left unsynchronised. The correct sequence:
bash-5.2# sync
bash-5.2# mount -o remount,ro /
bash-5.2# exec /sbin/init # start systemd from here
# or, if you would rather reboot:
bash-5.2# echo b > /proc/sysrq-triggerRecovering the root password
A classic scenario, and an uncomfortable demonstration of why physical access — or access to the hypervisor's console — amounts to control of the system:
# 1. GRUB menu -> e -> add at the end of the linux line:
# (change 'ro' to 'rw')
# rw init=/bin/bash
# 2. Ctrl+X
bash-5.2# export PATH=/usr/sbin:/usr/bin:/sbin:/bin
bash-5.2# mount -o remount,rw /
bash-5.2# passwd root
New password:
Retype new password:
passwd: password updated successfully
# 3. With SELinux (RHEL) you have to relabel; on Ubuntu with AppArmor it is not needed
bash-5.2# sync
bash-5.2# exec /sbin/initThe security lesson to draw from this: anybody with access to the machine's console can do it in two minutes. The countermeasures — a GRUB password with grub-mkpasswd-pbkdf2, full disk encryption with LUKS including /boot, Secure Boot, and physical access control — are precisely the ones that were left out of scope in the threat model of 06-06. Now you understand why that decision had to be explicit.
Recovering a system that will not boot
The scenario 05-04 announced: a broken fstab
You are going to cause it on purpose, because it is the most common failure after a change of disks and because in 06-05 you modified fstab for the LUKS volume.
# Cause the failure: a UUID that does not exist, with no nofail
$ sudo cp -p /etc/fstab /etc/fstab.bak-$(date +%F)
$ echo 'UUID=00000000-0000-0000-0000-000000000000 /data ext4 defaults 0 2' \
| sudo tee -a /etc/fstab
$ sudo mkdir -p /data
$ sudo rebootOn booting, instead of the login prompt you get:
[ FAILED ] Failed to mount /data. [DEPEND] Dependency failed for Local File Systems. You are in emergency mode. After logging in, type "journalctl -xb" to view system logs, ... Press Enter for maintenance (or press Control-D to continue):
This is exactly what mount -a would have prevented. The diagnosis and the repair:
# 1. Enter maintenance with the root password
Give root password for maintenance:
# 2. Confirm the cause
root@srv-tramontana:~# systemctl --failed --no-pager
UNIT LOAD ACTIVE SUB DESCRIPTION
● data.mount loaded failed failed /data
● local-fs.target loaded failed failed Local File Systems
root@srv-tramontana:~# journalctl -xb -u data.mount --no-pager | tail -3
mount: /data: can't find UUID=00000000-0000-0000-0000-000000000000.
# 3. Make the root writable and fix it
root@srv-tramontana:~# mount -o remount,rw /
root@srv-tramontana:~# nano /etc/fstab # comment out or correct the line
# 4. VERIFY before rebooting: the same safety net as 05-04
root@srv-tramontana:~# systemctl daemon-reload
root@srv-tramontana:~# mount -a && echo "fstab correct"
fstab correct
# 5. Continue the boot without rebooting
root@srv-tramontana:~# systemctl defaultAnd the two lessons, which go in the runbook:
mount -abefore rebooting, always. It is a two-second check that avoids this situation.nofailon every mount that is not essential for booting. Withnofail, a missing device produces a warning in the journal and the system boots. That is exactly why the backup volume's line carries it:
The (initramfs) prompt
A different and deeper failure: the initramfs has not managed to mount the root.
Gave up waiting for root file system device. ALERT! UUID=3f8a2c19-... does not exist. Dropping to a shell! BusyBox v1.36.1 (Ubuntu 1:1.36.1-6ubuntu3) built-in shell (ash) (initramfs)
The causes, with the check for each one:
# 1. See which devices the kernel detects: is a driver missing?
(initramfs) cat /proc/partitions
(initramfs) ls /dev/sd* /dev/nvme* 2>/dev/null
# 2. If the disk is there but it is LVM: activate the volumes by hand
(initramfs) lvm vgscan
(initramfs) lvm vgchange -ay
(initramfs) ls /dev/mapper/
# 3. If it is LUKS: unlock it by hand
(initramfs) cryptsetup luksOpen /dev/sda3 root-encrypted
(initramfs) lvm vgchange -ay
# 4. If it can be mounted by hand, the problem is configuration, not hardware
(initramfs) mkdir /rootfs && mount /dev/mapper/vg-root /rootfs && ls /rootfs
(initramfs) exit # BusyBox tries to continue the bootIf step 4 works, you know the disk and the filesystem are fine and that what is missing is in the initramfs or in crypttab. You boot with the previous kernel from the GRUB menu — whose initramfs is the one from before the change — and regenerate:
It is the reason keeping two kernels is a recovery measure, not a waste of space.
Reinstalling GRUB from rescue media
The most serious scenario: GRUB does not appear at all. The firmware finds nothing to boot, or boots straight into another system. It happens after installing another operating system, after cloning a disk, or after a firmware update that wiped the NVRAM entry.
You solve it by booting from external media (the Ubuntu ISO in Try Ubuntu mode), mounting the installed system and entering it with chroot — which is the conceptually interesting operation in this lesson, because it is the same primitive on which the containers of 07-05 are built.
# 1. Identify the partitions
ubuntu@ubuntu:~$ lsblk -f
NAME FSTYPE FSVER LABEL UUID MOUNTPOINTS
sda
├─sda1 vfat FAT32 A1B2-C3D4
├─sda2 ext4 1.0 7c4e1f92-3a8b-4d15-9e26-8f3a0b7c1d54
└─sda3 ext4 1.0 3f8a2c19-6b4d-4e71-a835-1c9e5f2d0a87
# 2. Mount the root, then /boot and the ESP INSIDE it
ubuntu@ubuntu:~$ sudo mount /dev/sda3 /mnt
ubuntu@ubuntu:~$ sudo mount /dev/sda2 /mnt/boot
ubuntu@ubuntu:~$ sudo mount /dev/sda1 /mnt/boot/efi
# 3. The four indispensable bind mounts.
# /dev -> access to the real devices
# /proc -> process and kernel information
# /sys -> the kernel's interface
# /sys/firmware/efi/efivars -> WRITING to the NVRAM (without this,
# grub-install fails under UEFI)
ubuntu@ubuntu:~$ for d in /dev /dev/pts /proc /sys /sys/firmware/efi/efivars /run; do
sudo mount --bind "$d" "/mnt$d"
done
# 4. Enter the installed system
ubuntu@ubuntu:~$ sudo chroot /mnt /bin/bash
root@ubuntu:/#That fourth mount is what makes half of all GRUB repair attempts fail under UEFI: without efivars accessible for writing, grub-install cannot create the boot entry and aborts with an error that does not explain the cause.
# 5. Reinstall GRUB and regenerate the configuration
root@ubuntu:/# grub-install --target=x86_64-efi --efi-directory=/boot/efi \
--bootloader-id=ubuntu --recheck
Installing for x86_64-efi platform.
Installation finished. No error reported.
root@ubuntu:/# update-grub
root@ubuntu:/# update-initramfs -u -k all
# 6. Check that the entry exists in the NVRAM
root@ubuntu:/# efibootmgr -v | grep -i ubuntu
Boot0000* ubuntu HD(1,GPT,...)/File(\EFI\ubuntu\shimx64.efi)
# 7. Exit cleanly: unmount in REVERSE ORDER
root@ubuntu:/# exit
ubuntu@ubuntu:~$ for d in /run /sys/firmware/efi/efivars /sys /proc /dev/pts /dev; do
sudo umount "/mnt$d"
done
ubuntu@ubuntu:~$ sudo umount /mnt/boot/efi /mnt/boot /mnt
ubuntu@ubuntu:~$ sudo rebootUnmounting in reverse order is not a formality: unmounting /mnt before /mnt/dev fails with target is busy, and forcing it can leave the filesystem marked as dirty.
For a system with BIOS/MBR instead of UEFI, step 5 changes and the efivars mounts do not apply:
Common Mistakes and Tips
- Editing
/boot/grub/grub.cfgby hand. The file says so on its third line. The changes disappear at the next kernel update. You edit/etc/default/gruband runupdate-grub. - Forgetting
update-gruborupdate-initramfsafter a change. Editing/etc/default/grubwithoutupdate-grubdoes nothing. Touchingcrypttabor LVM withoutupdate-initramfs -u -k allproduces the(initramfs)prompt on the next boot. - Regenerating the initramfs for the current kernel only. If you later need to boot with the previous one, you meet the same failure. Always
-k all. - Deleting old kernels by hand to free up
/boot. Being left with only one removes your safety net. Useapt autoremove --purge, which respects the running kernel and the previous one. - Mounts without
nofailinfstab. A missing device stops the machine booting. Only the root and/bootshould be able to block the boot. - Not running
mount -abefore rebooting. It is the two-second check that separates a warning from a session in emergency mode on the hypervisor's console. GRUB_TIMEOUT_STYLE=hiddenon a server. A hidden menu cannot be used to intervene. AndGRUB_TIMEOUT=0is worse: it removes the possibility of recovery through the menu.- Leaving
quiet splashin place when diagnosing. Remove them: the messages they hide are exactly the ones that say where it fails. - Forgetting
--bind /sys/firmware/efi/efivarsin the chroot.grub-installfails under UEFI with an unhelpful error. It is the most common cause of failed repairs. - Rebooting with
rebootfrominit=/bin/bash. There is no systemd to service the request.sync, remount read-only, andexec /sbin/initorecho b > /proc/sysrq-trigger. - A tip on method. Practise the three procedures — a broken
fstab, the root password, reinstalling GRUB — in the lab and with a snapshot taken first, today, calmly. The first time you need them will be at three in the morning with a service down, and that is no moment to be learning.
Exercises
Exercise 1
Deliberately cause the (initramfs) prompt in your lab and recover from it. Start from the fact that /srv/tramontana/backups is encrypted with LUKS and its key is declared in /etc/crypttab. Describe the change that causes the failure, why the system does not boot, how you diagnose it from the BusyBox prompt, and the two ways of recovering from it.
Exercise 2
srv-tramontana now takes 47 seconds to boot, where before it took 12. Describe the diagnostic procedure using systemd's tools, explaining what information each one contributes and how you tell a slow unit that does not matter from one that does.
Exercise 3
Marta asks you for a written boot recovery procedure for the runbook, one that somebody other than you could follow. Write it as a decision tree: what to observe, what to ask yourself and what to do on each branch, covering the four scenarios you have seen in the lesson.
Solutions
Solution 1
Causing the failure. The realistic scenario is a change in crypttab without regenerating the initramfs. Since the encrypted volume is the backup one and carries nofail, to make the failure a boot failure you have to touch something that does block. The clean way to reproduce it is to remove the LUKS and LVM modules from the initramfs:
$ sudo cp -p /etc/initramfs-tools/initramfs.conf{,.bak-$(date +%F)}
$ sudo cp -p /etc/crypttab /etc/crypttab.bak-$(date +%F)
# Empty crypttab: initramfs-tools reads it to decide whether to include cryptsetup
$ sudo truncate -s 0 /etc/crypttab
$ sudo sed -i 's/^MODULES=most/MODULES=dep/' /etc/initramfs-tools/initramfs.conf
$ sudo update-initramfs -u -k all
$ lsinitramfs /boot/initrd.img-$(uname -r) | grep -c cryptsetup
0
$ sudo rebootWhy it does not boot. The initramfs is the only environment that exists before the root is mounted, and its boot script needs cryptsetup to unlock the LUKS volume and lvm to activate the logical volumes. With neither included — because crypttab was empty when it was generated — the script does not find the root device, waits for the maximum time and drops to the BusyBox shell. It is the vicious circle from the initramfs section in its purest form: the tools for mounting the root are inside the root that cannot be mounted.
Diagnosis from BusyBox. Ruling things out from the outside in:
# 1. Does the kernel see the physical disk? If not, a DRIVER is missing
(initramfs) cat /proc/partitions
major minor #blocks name
8 0 26214400 sda
8 1 524288 sda1
8 2 976562 sda2
8 3 24712550 sda3The disk and its three partitions are there. The driver is ruled out.
No output: there is the cause. Neither of the two is in the initramfs.
# 3. Confirm the filesystem is healthy by mounting it by hand
(initramfs) blkid /dev/sda3
/dev/sda3: UUID="3f8a2c19-..." TYPE="ext4"
(initramfs) mkdir /rootfs && mount -o ro /dev/sda3 /rootfs
(initramfs) ls /rootfs
bin boot dev etc home lib opt proc root run sbin srv sys tmp usr varThe system is intact. The problem lies exclusively in the initramfs, and that is the conclusion that guides the repair.
The two ways of recovering from it.
Way A — boot with the previous kernel (the quick one). The initramfs of kernel 6.8.0-39 was generated before the change, so it is still complete... unless you used -k all, which is exactly what we did. If the update-initramfs had covered only the current one, this would be the way out in thirty seconds: GRUB menu → Advanced options → kernel 6.8.0-39 → boot → regenerate. The lesson is twofold: -k all is the correct thing to do so as not to leave a broken kernel behind, but it means a configuration mistake affects every kernel at once. That is why the check (lsinitramfs | grep cryptsetup) goes before the reboot, not after.
Way B — chroot from rescue media (the one that always works).
# Boot from the ISO in Try Ubuntu mode
ubuntu@ubuntu:~$ sudo cryptsetup luksOpen /dev/sda3 root # if the root is encrypted
ubuntu@ubuntu:~$ sudo mount /dev/sda3 /mnt
ubuntu@ubuntu:~$ sudo mount /dev/sda2 /mnt/boot
ubuntu@ubuntu:~$ sudo mount /dev/sda1 /mnt/boot/efi
ubuntu@ubuntu:~$ for d in /dev /dev/pts /proc /sys /sys/firmware/efi/efivars /run; do
sudo mount --bind "$d" "/mnt$d"; done
ubuntu@ubuntu:~$ sudo chroot /mnt /bin/bash
# Restore the configuration from the .bak copies you DID make
root@ubuntu:/# cp /etc/crypttab.bak-2026-08-18 /etc/crypttab
root@ubuntu:/# cp /etc/initramfs-tools/initramfs.conf.bak-2026-08-18 \
/etc/initramfs-tools/initramfs.conf
root@ubuntu:/# update-initramfs -u -k all
# VERIFY before rebooting
root@ubuntu:/# lsinitramfs /boot/initrd.img-6.8.0-41-generic | grep -c 'sbin/cryptsetup'
1
root@ubuntu:/# lsinitramfs /boot/initrd.img-6.8.0-39-generic | grep -c 'sbin/cryptsetup'
1
root@ubuntu:/# exit
ubuntu@ubuntu:~$ for d in /run /sys/firmware/efi/efivars /sys /proc /dev/pts /dev; do
sudo umount "/mnt$d"; done
ubuntu@ubuntu:~$ sudo umount /mnt/boot/efi /mnt/boot /mnt && sudo rebootAnd the two conclusions that go into the runbook: the .bak-$(date +%F) copies from the course's convention are what made the repair trivial — without them you would have to rebuild the configuration from memory — and the verification with lsinitramfs goes before the reboot, not after. The pattern is identical to mount -a for fstab: checking on the running system what would otherwise only show up at boot time.
Solution 2
The procedure starts by separating the kernel's boot from user space's boot, because they are different problems:
$ systemd-analyze
Startup finished in 3.398s (kernel) + 43.612s (userspace) = 47.010s
multi-user.target reached after 43.487s in userspace.The kernel takes as long as it always did (3.4 s); the extra 35 seconds are in user space. That rules out hardware, drivers and the initramfs, and focuses the search on the systemd units.
$ systemd-analyze blame | head -8
35.041s systemd-networkd-wait-online.service
4.187s [email protected]
2.098s snapd.service
1.874s cryptsetup@backups\x2dencrypted.service
938ms tramontana.service
610ms systemd-udev-settle.service
384ms fail2ban.service
122ms apparmor.serviceblame gives you the suspect, but it is not enough, and here is the substance of the exercise: a slow unit only matters if it is in the critical chain. You have to check:
$ systemd-analyze critical-chain
The time when unit became active or started is printed after the "@" character.
The time the unit took to start is printed after the "+" character.
multi-user.target @43.487s
└─tramontana.service @42.540s +938ms
└─postgresql.service @42.536s
└─network-online.target @42.530s
└─systemd-networkd-wait-online.service @7.489s +35.041s
└─systemd-networkd.service @7.203s +281msConfirmed. systemd-networkd-wait-online is in the chain, takes 35 s, and drags along everything that depends on the network: PostgreSQL waits for network-online.target, and tramontana.service waits for PostgreSQL. The 35 s propagate in full to the total.
The contrast the question asks for is provided by snapd.service: it takes 2 seconds and does not appear in the critical chain, because it starts in parallel and nothing waits for it. Optimising it would not save a tenth of a second off the total. That is the difference between the two tools:
| Tool | What it answers | Risk of misreading it |
|---|---|---|
systemd-analyze |
Kernel or user space? | None; it is the first filter |
blame |
Which unit took longest? | High: a slow unit running in parallel delays nothing |
critical-chain |
What determines the total time? | Low; it is where you should optimise |
journalctl -b |
Why did it take so long? | None; it is the root cause |
The root cause, with the journal:
$ journalctl -b -u systemd-networkd-wait-online --no-pager
systemd-networkd-wait-online[701]: Timeout occurred while waiting for network connectivity.
systemd-networkd-wait-online[701]: Event loop failed: Connection timed out.
$ networkctl status enp0s3 | grep -E 'State|Online'
State: routable (configured)
Online state: online
$ networkctl list
IDX LINK TYPE OPERATIONAL SETUP
1 lo loopback carrier unmanaged
2 enp0s3 ether routable configured
3 virbr0 bridge no-carrier configuredThere it is: virbr0, libvirt's bridge, is configured but has no carrier, because there is no virtual machine running connected to it. By default systemd-networkd-wait-online waits for all managed interfaces to be online, and that one never will be. The 35 seconds are its maximum wait running out.
The fix is to tell it which interface actually matters:
$ sudo mkdir -p /etc/systemd/system/systemd-networkd-wait-online.service.d
$ sudo tee /etc/systemd/system/systemd-networkd-wait-online.service.d/override.conf >/dev/null <<'EOF'
[Service]
ExecStart=
ExecStart=/usr/lib/systemd/systemd-networkd-wait-online --interface=enp0s3 --timeout=30
EOF
$ sudo systemctl daemon-reloadThe empty ExecStart= before the new one is compulsory: without it, systemd adds a second command instead of replacing the first, and the unit fails. It is the same list-reset mechanism you saw with SystemCallFilter in 06-06.
And the verification, with the discipline of measuring before and after:
$ sudo reboot
# ... after the reboot
$ systemd-analyze
Startup finished in 3.402s (kernel) + 9.118s (userspace) = 12.520s
$ systemd-analyze critical-chain | head -5
multi-user.target @8.993s
└─tramontana.service @8.046s +938ms
└─postgresql.service @8.041s
└─network-online.target @8.034s
└─systemd-networkd-wait-online.service @7.492s +541ms
$ ~/scripts/health_check.sh; echo "status: $?"
status: 0From 47 s to 12.5 s, with the service verified. And a reflection on method: the symptom ("the boot is taking longer") appeared after libvirt was installed, and nobody connected the two things. Recording the boot time in the runbook as part of the 05-07 baseline is what turns "it feels slower to me" into a dated piece of data.
Solution 3
RUNBOOK — Boot recovery for
srv-tramontanaVersion 1.0 · 18 August 2026 · Author: Systems Operations This document is kept OFF the server. A copy on the administration laptop and in the team's password manager.Prerequisites. Access to the machine's console in VirtualBox (SSH will not do: if it does not boot, there is no network). The root password, available at
pass tramontana/production/root. An Ubuntu Server 24.04 ISO available for case 4.
STEP 0 — The only question that matters: how far did it get?
Power on the machine and watch. Do not touch anything yet. Note the time and what you see on screen.
What you see It broke at Go to case A black screen, no logo, no menu Firmware or GRUB Case 4 The GRUB menu, but it goes no further GRUB or the kernel Case 4 The (initramfs)promptinitramfs Case 3 Boot messages and then emergency modeFilesystem mounting Case 1 It boots but you cannot log in Authentication Case 2 It boots, but very slowly None; it is a slow unit Case 5
CASE 1 — "You are in emergency mode" (the most frequent)
It is nearly always
/etc/fstab, after a change of disks.
- Press
Enterand type the root password.- Identify what failed:
systemctl --failed- Read the cause:
journalctl -xb | tail -30- Make the root writable:
mount -o remount,rw /- Correct
/etc/fstabwithnano. If in doubt, comment out the suspect line by putting#in front of it: it is reversible and it gives you the service back.- Verify without rebooting:
systemctl daemon-reload && mount -a
- No errors → step 7.
- Errors → back to step 5. Do not reboot while
mount -ais failing.- Continue the boot:
systemctl default- Check the service:
/home/operator/scripts/health_check.sh(it must return 0).Note: if the problem line is the one for
/srv/tramontana/backups, it should carrynofailand not block the boot. If it did block it, addnofailas part of the fix.
CASE 2 — It boots but you cannot log in
- Reboot. In the GRUB menu, with the Ubuntu entry selected, press
e. (If the menu does not appear: holdShiftor pressEscrepeatedly while powering on.)- On the line starting with
linux /vmlinuz-, changerotorwand add at the end:init=/bin/bashCtrl+Xto boot.- At the
bash-5.2#prompt:export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin mount -o remount,rw / passwd root # or: passwd operator- If the cause was a change in PAM (
/etc/pam.d/), restore the copy:cp /etc/pam.d/common-auth.bak-<date> /etc/pam.d/common-auth- Clean exit — do not use
reboot, there is no systemd:sync exec /sbin/init
CASE 3 — The
(initramfs)promptIt usually comes from a change to
crypttab, LVM or the disks without regenerating the initramfs.
- Check whether the kernel sees the disk:
cat /proc/partitions
- The disk does not appear → a hardware or driver problem. Escalate; check the VM's storage configuration.
- It appears → carry on.
- Check whether the tools are present:
which cryptsetup lvm
- No output → they are missing from the initramfs. Go to step 4.
- Try mounting by hand to confirm the data is intact:
lvm vgchange -ay mkdir /rootfs && mount -o ro /dev/mapper/<volume> /rootfs && ls /rootfs- Quick recovery: reboot, and in the GRUB menu go into Advanced options for Ubuntu and choose the previous kernel. If it boots:
sudo update-initramfs -u -k all sudo lsinitramfs /boot/initrd.img-$(uname -r) | grep -c sbin/cryptsetup # must give 1- If the previous kernel will not boot either: go to Case 4 (chroot) and run the step 4 commands from there.
CASE 4 — No GRUB, or none of the above works: the rescue chroot
A universal procedure. It requires the Ubuntu 24.04 ISO mounted in the VM and booting in Try Ubuntu mode.
- Identify the partitions:
lsblk -fsrv-tramontanareference:sda1= ESP (FAT32),sda2=/boot,sda3= root.- Mount, in this order:
⚠️sudo mount /dev/sda3 /mnt sudo mount /dev/sda2 /mnt/boot sudo mount /dev/sda1 /mnt/boot/efi for d in /dev /dev/pts /proc /sys /sys/firmware/efi/efivars /run; do sudo mount --bind "$d" "/mnt$d" doneefivarsis not optional. Without it,grub-installfails under UEFI with an unclear error.- Enter:
sudo chroot /mnt /bin/bash- Repair whatever applies:
grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=ubuntu --recheck update-grub update-initramfs -u -k all efibootmgr -v | grep -i ubuntu # the entry must appear- Clean exit, unmounting in reverse order:
exit for d in /run /sys/firmware/efi/efivars /sys /proc /dev/pts /dev; do sudo umount "/mnt$d" done sudo umount /mnt/boot/efi /mnt/boot /mnt sudo reboot
CASE 5 — It boots, but takes far longer than usual
This is not an emergency. Normal reference: ~12 seconds.
systemd-analyze→ separates the kernel from user space.systemd-analyze critical-chain→ this is the one that matters, notblame: a slow unit that starts in parallel does not delay the total.journalctl -b -u <unit>→ the specific cause.- Fix it with a drop-in in
/etc/systemd/system/<unit>.d/override.conf, never by editing the original unit. If you are replacing anExecStart, remember the emptyExecStart=line first.- Reboot and measure again. Record the new time in the baseline.
RULES THAT PREVENT THE FIRST FOUR CASES
Before… Always do Rebooting after touching fstabmount -aand check that it gives no errorRebooting after touching crypttab, LVM or the disksupdate-initramfs -u -k alland verify withlsinitramfs | grep cryptsetupTouching PAM or sshd_configA second session open; validate with sshd -t;reload, notrestartAny configuration change A .bak-$(date +%F)copy anddiff -uafterwardsAny delicate module A snapshot of the VM, numbered Never:
GRUB_TIMEOUT=0,GRUB_TIMEOUT_STYLE=hidden, deleting kernels by hand, or mounts withoutnofailother than the root and/boot.If nothing works. Do not improvise for more than 30 minutes. Rebuild: the agreed RTO is 8 hours, the rebuild runbook is in this same document, and the data is in
resticwith a tested restore. Tell Operations before you start.
Conclusion
You no longer just boot a server: you know what happens when you do. You know the complete chain — UEFI firmware, the ESP and efibootmgr, GRUB with its real configuration sources, the initramfs and the vicious circle it solves, the kernel and its handover of control to PID 1, and systemd activating default.target — and, above all, you know how to use that chain as a diagnostic tool: the first question when faced with a server that will not boot is always how far did it get. You have intervened in the GRUB menu, you have told rescue from emergency, you have booted with a shell as PID 1 and you have understood why the root is read-only. You have repaired a broken fstab — the scenario 05-04 left announced — you have recovered a root password in two minutes (and with it seen why physical access was left out of the threat model of 06-06), and you have reinstalled GRUB from rescue media with the complete chroot, including the --bind of efivars that makes half of all attempts fail. The runbook now has a decision tree that somebody other than you could follow, which is the definition of a useful procedure.
And along the way you have used chroot to enter somebody else's filesystem and run programs inside it as though it were the root. Remember that: it is the primitive on which everything you will see in 07-05 is built, when you discover that a container is not a small machine.
You know how to look at the boot, but you still do not know how to look inside a running process. In Module 5 you learned to measure with the USE method: vmstat, iostat, free and sar tell you the CPU is at 80%, the disk has high latency or memory is running out. That answers how much, but not what. When health_check.sh starts returning 1 because the application takes 400 ms to respond instead of 40, and the counters say the CPU is idle, the disk quiet and memory plentiful, you will need a different class of tool. In lesson 07-02: Advanced Diagnostics you will learn to ask the system what exactly a process is doing: strace to see its system calls one by one — closing the circle with the layers from Module 1 — perf to profile where it really burns cycles and to read a flame graph, and eBPF with bpftrace and the bpfcc-tools utilities to instrument the kernel in production without strace's prohibitive cost. And you will run head-on into a consequence of your own work: the kernel.yama.ptrace_scope = 1 you applied in 06-06 is going to stop you attaching to your own processes, and understanding why that is a good thing is part of the lesson.
Linux Course: From Beginner to System Administrator
Module 1: Introduction to Linux
- What Is Linux?
- History of Linux
- Linux Distributions
- Installing Linux
- First Contact with the System
- The Linux File System Structure
Module 2: Basic Linux Commands
- Introduction to the Command Line
- Getting Help and System Documentation
- Navigating the File System
- File and Directory Operations
- Viewing and Editing Files
- Hard and Symbolic Links
- File Permissions and Ownership
Module 3: Advanced Command-Line Skills
- The Shell Environment: Variables, Aliases and History
- Using Wildcards and Regular Expressions
- Searching Files and Content: find, locate and grep
- Pipes and Redirection
- Text Processing: cut, sort, uniq, sed and awk
- Process Management
- Scheduling Tasks with Cron
- Networking Commands
Module 4: Shell Scripting
- Introduction to Shell Scripting
- Variables and Data Types
- Script Input, Output and Arguments
- Control Structures
- Functions and Libraries
- Debugging and Error Handling
- Production Scripts: Best Practices
Module 5: System Administration
- User and Group Management
- sudo and Special Permissions
- Package Management
- Disk Management
- systemd and Service Management
- System Logs: journald and syslog
- System Monitoring and Performance Tuning
- Backup and Restore
Module 6: Networking and Security
- Network Configuration
- SSH and Remote Access
- Firewalls and Perimeter Security
- Intrusion Detection Systems
- Secrets Management and TLS Certificates
- Securing Linux Systems
Module 7: Advanced Topics
- The Boot Process and System Recovery
- Advanced Diagnostics: strace, perf and eBPF
- Linux Kernel Tuning
- Virtualization with Linux
- Linux Containers and Docker
- Automation with Ansible
- High Availability and Load Balancing
