DevOps.Academy
CoursesCurriculumPricing

    Loading…

    ↑ ↓ move · ↵ open · Ctrl K anywhere

    ◔My learningSign in
    DevOps.Academy

    Free, hands-on DevOps lessons. Made with care in India.

    Learn

    All coursesLinux roadmapCurriculumMy learning

    Academy

    PricingCertificates

    Legal

    PrivacyTermsContact

    devops.rajeev.pro

    Linux & BashLesson 12 of 16
    Your progress · 0%
    On this page
    1. The boot, stage by stage
    2. The boot loader: GRUB
    3. systemd targets
    4. Reading boot logs
    5. When a server will not boot
    ↖ Course roadmap
    Lesson 12 · Booting Linux

    How Linux boots, and what to do when it does not

    How Linux boots, from firmware through GRUB, the kernel and initramfs to systemd targets. Read boot logs, find slow boots, and recover a server that won't start.

    30 min read · intermediate · hands-on

    By the end of this lesson you'll be able to

    0 of 6 complete

    The boot, stage by stage

    Between pressing power and seeing a login prompt, five programs take turns. Each one finds and starts the next:

    Firmware, GRUB, kernel, initramfs, systemd. Where a boot stops tells you which one to fix.© Animation: DevOps Academy

    Firmware, GRUB, kernel, initramfs, systemd. Where a boot stops tells you which one to fix.© Animation: DevOps Academy
    StageDoesFails like
    Firmware (UEFI, BIOS)Tests hardware, finds a boot disk"No bootable device"
    Boot loader (GRUB)Loads the kernel and initramfs from /bootgrub rescue> prompt
    KernelStarts drivers, mounts the initramfsKernel panic
    initramfsFinds the real root filesystem and mounts itDrops to an (initramfs) shell
    systemd (PID 1)Starts services up to the default targetEmergency mode, a failed service

    On a cloud VM you never see the screen, so the first two stages are the provider's job, and almost every boot problem you'll fix is in the last one: systemd and /etc/fstab.

    The boot loader: GRUB

    GRUB shows the boot menu (it's hidden on most servers) and starts the kernel with its options. You never edit its generated file, /boot/grub/grub.cfg. You edit the settings and regenerate it:

    # /etc/default/grub (excerpt)
    GRUB_DEFAULT=0                      # which menu entry boots: 0 is the newest kernel
    GRUB_TIMEOUT=5                      # seconds the menu waits
    GRUB_CMDLINE_LINUX_DEFAULT="quiet"  # options passed to the kernel at every boot
    
    $ sudo nano /etc/default/grub
    $ sudo update-grub                          # Ubuntu, Debian: rebuild grub.cfg
    $ sudo grub2-mkconfig -o /boot/grub2/grub.cfg   # RHEL family
    $ cat /proc/cmdline                         # the options the running kernel booted with
    $ ls /boot                                  # kernels (vmlinuz-*) and initramfs images (initrd.img-*)
    
    sudo nano /etc/default/grub
    • sudorun the next command as root
    cat /proc/cmdline
    • catprint a file
    ls /boot
    • lslist files

    Package upgrades install new kernels and update GRUB for you, keeping the previous kernel. If a new kernel misbehaves, pick the older one from the GRUB menu (hold Shift or press Esc at boot) under Advanced options.

    systemd targets

    When the kernel and initramfs are done, they start systemd as process 1. systemd boots towards a target: a named group of units that make up a system state. They replaced the old runlevels:

    TargetOld runlevelState
    poweroff.target0off
    rescue.target1single user, minimal services, for repairs
    multi-user.target3a normal server: networking, services, no desktop
    graphical.target5multi-user plus a desktop
    reboot.target6reboot
    emergency.targetroot shell, almost nothing mounted
    $ systemctl get-default                       # the target this machine boots into
    graphical.target
    $ sudo systemctl set-default multi-user.target   # servers don't need a desktop
    $ sudo systemctl isolate rescue.target        # switch now (this stops most services)
    $ systemctl list-dependencies multi-user.target | head
    
    systemctl get-default
    • systemctlcontrol systemd services
    sudo systemctl set-default multi-user.target
    • sudorun the next command as root
    systemctl list-dependencies multi-user.target | head
    • |pipe: send output to the next command
    • headshow the first lines

    Your services join the boot through targets: the WantedBy=multi-user.target in a unit file (from the Services with systemd lesson) is what enable links them into.

    Reading boot logs

    $ journalctl --list-boots                     # every boot the journal remembers
    IDX BOOT ID                          FIRST ENTRY                 LAST ENTRY
     -1 7c1d93e0a4b24f6e8d1f2a3b5c6d7e8f Sun 2026-10-11 05:47:21 UTC Mon 2026-10-12 23:58:02 UTC
      0 bea482c8f6f84fe4b096e875c660d327 Tue 2026-10-13 00:01:15 UTC Tue 2026-10-13 05:29:13 UTC
    $ journalctl -b                               # this boot, from the first kernel line
    $ journalctl -b -1 -p err                     # errors from the previous boot
    $ journalctl -b -1 -n 50                      # the last 50 lines before the last reboot
    $ sudo dmesg -T | grep -iE "error|fail|oom"   # kernel messages with readable times
    $ systemctl --failed                          # units that failed this boot
    
    journalctl --list-boots
    • journalctlread the systemd journal (logs)
    journalctl -b
    • -bsince this boot
    journalctl -b -1 -p err
    • -pminimum priority, like err
    journalctl -b -1 -n 50
    • -nhow many lines
    sudo dmesg -T | grep -iE "error|fail|oom"
    • sudorun the next command as root
    • |pipe: send output to the next command
    • grepfind lines that match a pattern
    systemctl --failed
    • systemctlcontrol systemd services

    journalctl -b -1 is how you answer "why did it reboot at 3 am?". It needs the journal on disk: check that /var/log/journal/ exists (it does on modern Ubuntu). The end of the previous boot often shows the cause: an out-of-memory kill, a kernel panic, or a clean reboot someone ran.

    Why is the boot slow?

    $ systemd-analyze                             # total boot time
    Startup finished in 2.1s (kernel) + 8.939s (userspace) = 11.039s
    graphical.target reached after 8.939s in userspace.
    $ systemd-analyze blame | head -5             # units by start time
    $ systemd-analyze critical-chain              # the chain the boot actually waited on
    
    systemd-analyze blame | head -5
    • |pipe: send output to the next command
    • headshow the first lines

    blame can mislead: a slow unit that runs in parallel doesn't delay anything. critical-chain shows what the boot was really waiting for. A common culprit on servers is systemd-networkd-wait-online.service waiting for a network interface that never comes up.

    When a server will not boot

    In production: get a console first

    You can't SSH into a server that didn't finish booting. Every cloud has a way in: AWS EC2 Serial Console, Azure Serial Console, GCP serial port. Set it up and test it before the day you need it. The other way out: stop the VM, attach its disk to a healthy one, and fix the files there.

    You seeUsuallyFix
    "You are in emergency mode"A bad /etc/fstab lineLog in as root, mount -o remount,rw /, fix /etc/fstab, systemctl daemon-reload, reboot
    (initramfs) promptRoot filesystem not found or damagedfsck the root device from that shell, or boot the previous kernel
    Boot hangs on a "start job"A service or mount waiting foreverBoot into rescue, find it with journalctl -b -1, fix or disable it
    Kernel panic after an upgradeThe new kernel or its initramfsPick the previous kernel in GRUB, then reinstall or remove the new one

    To reach a root shell when you have a console but no password: at the GRUB menu press e, add systemd.unit=rescue.target to the end of the line starting with linux, and press Ctrl+X. That one change boots without most services, so you can repair things.

    ⌘
    Mini mission

    Write a boot report for a server that rebooted

    A server restarted overnight and the team wants to know when, why, and whether everything came back. Collect the boot history, errors from the previous boot, units that failed this boot, and the boot time, into one file.

    Input: Any Linux server running systemdOutput: ~/boot-report.txt
    Reveal one safe solution
    $ cat > ~/boot-report.sh <<'EOF'
    #!/bin/bash
    echo "== boots"; journalctl --list-boots --no-pager | tail -3
    echo "== up since: $(uptime -s)"
    echo "== default target: $(systemctl get-default)"
    echo "== last lines of the previous boot"; journalctl -b -1 -n 15 --no-pager 2>/dev/null || echo "(no previous boot stored)"
    echo "== errors in the previous boot"; journalctl -b -1 -p err --no-pager 2>/dev/null | tail -10
    echo "== failed units now"; systemctl --failed --no-legend --no-pager
    echo "== boot time"; systemd-analyze 2>/dev/null | head -1
    EOF
    $ bash ~/boot-report.sh > ~/boot-report.txt
    $ head -8 ~/boot-report.txt
    == boots
    IDX BOOT ID                          FIRST ENTRY                 LAST ENTRY
      0 bea482c8f6f84fe4b096e875c660d327 Sun 2026-10-11 05:47:21 UTC Tue 2026-10-13 05:29:13 UTC
    == up since: 2026-10-11 05:47:21
    == default target: graphical.target
    == last lines of the previous boot
    (no previous boot stored)
    == errors in the previous boot
    
    cat > ~/boot-report.sh <<'EOF'
    • catprint a file
    • >write output to a file, replacing it
    head -8 ~/boot-report.txt
    • headshow the first lines

    Run it with sudo to include the system journal on machines where your user can't read it. The last lines of the previous boot are the part to read closely: a clean shutdown ends with systemd stopping services; a crash or power loss just stops.

    Try it yourself

    0 of 6 steps done

    Run each task in your own account or terminal, then tick it off.

    Knowledge check

    Quick check

    Question 1 of 5

    You edited /etc/default/grub. What makes the change take effect at the next boot on Ubuntu?

    Go deeper

    Official reading for this lesson

    • Docsbootup(7): the system boot-up processUbuntu manpages ↗
    • Docssystemd.special(7): the special targetsUbuntu manpages ↗
    • Docssystemd-analyze(1) manualUbuntu manpages ↗
    • Docsjournalctl(1) manualUbuntu manpages ↗
    • GuideLPIC-1 objectives 101.2, 101.3 and 102.2Linux Professional Institute ↗

    Or get every quiz answer right and it completes itself.

    ← PreviousDisks and filesystems: add, mount, grow and repairNext lesson →Networking: addresses, DNS, routes and SSH