The Boot Process & Targets
When you press the power button on an Ubuntu server, a precise chain of events runs before you ever see a login prompt. Understanding this chain — firmware, then a bootloader, then the kernel, then systemd — helps you fix servers that won’t start, choose whether a machine boots to a desktop or a plain terminal, and reason about why services come up in a certain order. This page walks through each stage in plain English and shows you the exact commands to inspect and control it on Ubuntu 22.04 and 24.04 LTS.
The boot sequence, stage by stage
Booting is a hand-off race: each stage starts the next, then steps out of the way. Here is the full chain on a modern Ubuntu server.
- Firmware (UEFI or BIOS) — The first code that runs, stored on a chip on the motherboard. UEFI (Unified Extensible Firmware Interface) is the modern standard; BIOS (Basic Input/Output System) is the old one. The firmware runs a quick hardware check (POST, the Power-On Self-Test), then looks for a bootloader on disk and runs it.
- GRUB (the bootloader) — GRUB (GRand Unified Bootloader) is a small program whose only job is to load an operating system. It shows the boot menu, then loads the Linux kernel (the core of the operating system that talks to hardware) into memory and starts it.
- The kernel — The kernel initializes hardware (CPU, memory, disks, network cards), mounts the root filesystem, and then starts the very first user-space program, called init. On Ubuntu, that init program is systemd.
- systemd (PID 1) — systemd is the system and service manager. It always runs as process ID 1 (PID 1). It starts everything else — networking, logging, your web server, your database — in the right order, then brings the system to its default target (more on targets below).
# See how long each stage took on the last boot
systemd-analyze
Output:
Startup finished in 4.512s (firmware) + 2.103s (loader) + 1.884s (kernel) + 6.220s (userspace) = 14.720s
graphical.target reached after 6.210s in userspace.
Tip: To find what is slowing your boot, run
systemd-analyze blame. It lists every service ranked by how long it took to start, so you can spot the slow one.
GRUB: choosing what boots
GRUB is where you pick a kernel (Ubuntu keeps the old one as a fallback) or enter recovery mode (a minimal boot used for repairs). On a server you usually let it boot automatically, but you control its behavior through a config file.
You never edit GRUB’s generated config directly. Instead you edit /etc/default/grub and regenerate.
sudo nano /etc/default/grub
# /etc/default/grub
GRUB_DEFAULT=0
GRUB_TIMEOUT=5
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
GRUB_CMDLINE_LINUX=""
GRUB_TIMEOUT— how many seconds the menu waits before booting the default entry.GRUB_DEFAULT— which menu entry boots by default (0 is the first).
After any change, regenerate the real config so GRUB picks it up.
sudo update-grub
Output:
Sourcing file `/etc/default/grub'
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-6.8.0-31-generic
Found initrd image: /boot/initrd.img-6.8.0-31-generic
done
systemd targets replace runlevels
Older Linux systems used runlevels — numbered states (0–6) that defined what the machine was doing (halted, single-user, multi-user, etc.). systemd replaced runlevels with targets: named groups of services that represent a system state. Targets are more flexible because a target can depend on other targets and services by name instead of by number.
The two you care about most on a server:
| Target | Old runlevel | What it means | When to use it |
|---|---|---|---|
multi-user.target | 3 | Full system, networking on, no graphical desktop — just text consoles and SSH | The normal choice for servers — no wasted memory on a GUI |
graphical.target | 5 | Everything in multi-user plus a graphical login screen and desktop | Desktops and workstations, or a server you manage with a GUI |
rescue.target | 1 (single-user) | Minimal system, root shell, most services stopped | Repairing a broken system |
emergency.target | — | Bare minimum, root filesystem mounted read-only | Last-resort recovery when even rescue fails |
reboot.target | 6 | Restarts the machine | Triggered by reboot |
poweroff.target | 0 | Shuts the machine down | Triggered by poweroff |
Getting and setting the default target
The default target is the state systemd brings the machine to at the end of boot. On a fresh Ubuntu Server install it is multi-user.target; on Ubuntu Desktop it is graphical.target.
Check the current default.
systemctl get-default
Output:
graphical.target
To save memory on a server, switch the default to text-only multi-user.target. This survives reboots.
sudo systemctl set-default multi-user.target
Output:
Removed /etc/systemd/system/default.target.
Created symlink /etc/systemd/system/default.target → /usr/lib/systemd/system/multi-user.target.
Gotcha:
set-defaultonly changes what happens on the next boot. To switch the running system right now without rebooting, useisolate(below).
You can also change the active target immediately. isolate starts the named target and stops anything not part of it.
# Switch the live system to text-only mode right now
sudo systemctl isolate multi-user.target
To inspect what is going on, list targets and view the boot default.
# Show all loaded targets and whether they are active
systemctl list-units --type=target
Output:
UNIT LOAD ACTIVE SUB DESCRIPTION
basic.target loaded active active Basic System
cryptsetup.target loaded active active Local Encrypted Volumes
getty.target loaded active active Login Prompts
multi-user.target loaded active active Multi-User System
network-online.target loaded active active Network is Online
sysinit.target loaded active active System Initialization
To boot into a different target just once (for troubleshooting), add its name at the GRUB menu: press e on the boot entry, append systemd.unit=rescue.target to the linux line, then press Ctrl+X to boot. The change is temporary and does not touch your config.
Best Practices
- Run servers in
multi-user.target— a GUI wastes RAM and CPU and widens the attack surface for no benefit on a headless machine. - Always edit
/etc/default/gruband then runsudo update-grub; never hand-edit/boot/grub/grub.cfg, because it is overwritten on the next kernel update. - Use
systemd-analyze blameafter install to catch services that slow your boot, and disable ones you do not need withsudo systemctl disable <service>. - Keep
GRUB_TIMEOUTat a few seconds on physical servers so you can reach recovery mode, but consider a shorter value on cloud VMs that you never see a console for. - Test a new default target with
systemctl isolatebefore committing to it withset-default, so you can confirm the system behaves before a reboot locks it in. - Know your escape hatch: appending
systemd.unit=rescue.targetat the GRUB menu gets you a root shell when a bad config blocks a normal boot.