Learn Linux Startup Modes the Easy Way

Systemd targets boot modes Linux explained terminal commands


Systemd targets boot modes Linux explained terminal commands

Systemd targets boot modes Linux explained: Set your server to the wrong boot target and watch services mysteriously fail to start on the next reboot, even though the system boots fine. You reboot, nothing loads, and you're left staring at a login prompt wondering what happened. This is what happens when the concept of systemd targets boot modes and runlevels stays fuzzy. Most Linux admins learn this the hard way in production.

Default Target graphical.target or multi-user.target (systemd)
Check Current systemctl get-default
Change Target systemctl set-default multi-user.target
Old System Runlevels Runlevels 0-6 (SysV init, mostly obsolete)

Systemd Targets Boot Modes: What Linux Boot Targets Actually Do

A boot target is systemd's way of grouping services and defining what runs when your server starts. Think of it as a preset configuration. Want a graphical desktop? Load graphical.target. Running a headless database server? Use multi-user.target. Each target is just a collection of services and settings that systemd knows to activate together.

The old system used runlevels, numbered 0 through 6, each with a specific purpose. Runlevel 3 meant multi-user command line, runlevel 5 meant graphical, and so on. Modern Linux systems replaced this with targets because systemd units are more flexible and explicit about what they actually do. Instead of memorizing that runlevel 2 does something different on Debian than Fedora, you just ask: does this target pull in a display manager or not?

Here's what matters for your server: the boot target determines which services auto-start. Set the wrong target and critical services simply do not load. Set it right and everything you need launches automatically. Most server problems boil down to either the wrong target chosen or a service that depends on a target that is not running.

Key Points:

  1. Boot targets are systemd's way to group services for different boot scenarios.
  2. graphical.target loads the full desktop and all its dependencies.
  3. multi-user.target skips the display manager and runs a command-line-only environment.
  4. Knowing which one you need for your server type prevents boot-time service failures.

How Linux Systemd Targets Boot Modes Work Under the Hood

Most Linux documentation glosses over this, which is exactly why people get confused. Let's break it down properly so you understand what is actually happening when systemd starts.

What the Old Runlevels Did

In the SysV init era, the kernel would tell init to enter a specific runlevel. Init would then scan /etc/rc.d directories, find scripts matching that runlevel, and execute them in order. Runlevel 3 meant no GUI, runlevel 5 meant load X11. But here is the problem: different distros implemented runlevels differently, and the system did not really know dependencies between services. If you wanted networking before starting a database, you had to manually order the startup scripts. It was a mess.

How Systemd Replaced Them

Systemd replaced runlevels with targets. A target is just a special systemd unit file that groups other units (services, sockets, etc.) together. When you boot into graphical.target, systemd reads that target file, sees which services and units it requires, and activates them as a dependency graph. Services can declare "I require networking" or "I want the display manager" and systemd ensures those are available first. This is far more explicit and reliable.

The Target Unit Structure

Every target is stored as a .target file in /usr/lib/systemd/system/ or /etc/systemd/system/. The graphical.target file contains directives like Requires= and Wants= that pull in other services. There is also Conflicts= which says "if this target is running, do not start that service." This prevents you from accidentally running both a display manager and something that should not run in GUI mode at the same time.

Understanding Legacy Runlevels (For Older Systems)

If you ever touch a system still running SysV init instead of systemd, you will encounter runlevels. Runlevels are numbered 0 through 6, each representing a different state of the machine. They are mostly gone now, but you might still see them referenced in startup scripts or documentation. The mapping between old runlevels and modern targets tells you exactly what they meant.

Runlevel 0 meant shut down. Runlevel 1 was rescue mode for maintenance. Runlevel 3 was the standard multi-user command-line environment that servers lived in. Runlevel 5 was graphical mode. Runlevel 6 was reboot. The others (2 and 4) varied by distribution, which was part of the problem with the old system. You could never be sure what runlevel 2 meant on Debian versus Red Hat without checking documentation.

The command to check and change runlevels on old systems was simple: runlevel to check, init 3 to change to runlevel 3. Modern systems still have these commands as compatibility wrappers that call systemd, but they are not the real thing anymore. systemd.target official documentation

How Runlevels Map to Modern Targets

systemd maintains a compatibility layer so old runlevel commands still work. Here is the exact mapping so you understand what you are looking at on any Linux system.

Legacy Runlevel Meaning Modern Systemd Target
0 System halt / poweroff poweroff.target
1 Single-user / rescue mode rescue.target
2 Multi-user / Varies by legacy distro (Default graphical in Debian/Ubuntu, CLI in RHEL) multi-user.target
3 Multi-user with networking, CLI only multi-user.target
4 Custom / unused (distribution specific) multi-user.target
5 Multi-user with graphical interface graphical.target
6 System reboot reboot.target

If you run init 3 on a modern system, systemd translates that to systemctl isolate multi-user.target behind the scenes. If you run runlevel, it still returns the old runlevel number, but systemd is simulating it. This backwards compatibility is why you can still use old commands, but they are not actually doing what they used to do.

What Init Really Is

Init is the first process that starts after the kernel boots. It has PID 1. In old systems, init was an actual program called /sbin/init that read configuration files and executed startup scripts. In modern systems, init is a symlink that points to /lib/systemd/systemd. When the kernel boots, it starts systemd as PID 1, and systemd becomes the parent of all other processes. Everything else depends on it. If systemd crashes, the entire system fails catastrophically because nothing else can manage child processes.

You can verify this on any modern Linux system by running ps -p 1 or checking what /sbin/init points to. The output will show systemd is running as PID 1. This is why systemd is so critical and why understanding how it manages boot targets matters so much.

Performance Impact Across Targets:

graphical.target loads the display manager, X11 (or Wayland), and desktop environment services. This adds overhead even if you never use the GUI remotely. For servers, multi-user.target is significantly leaner because it skips all graphics stack dependencies. A database server on graphical.target boots slower and consumes more memory for services you do not need. This is why cloud providers default servers to multi-user.target.

Systemd Targets Boot Modes: Practical Commands on Ubuntu and Rocky Linux

Now the part you actually use. Every major Linux distro runs systemd now, but the paths and some package names differ slightly between Ubuntu and Rocky Linux. Let's walk through the exact commands for each.

Check Your Current Boot Target on Ubuntu

First thing to verify: what target is your system currently set to load on boot?

bash
LinuxTeck.com
systemctl get-default
OUTPUT
graphical.target

This returns which target will load on the next boot. If you see graphical.target, your Ubuntu machine loads the desktop environment. If you see multi-user.target, it boots to command line only.

Check Your Current Boot Target on Rocky Linux

Rocky Linux uses the exact same command. systemd is systemd regardless of the distro.

bash
LinuxTeck.com
systemctl get-default
OUTPUT
multi-user.target

Most Rocky Linux servers default to multi-user.target because they are headless servers in data centers, not workstations.

List All Available Boot Targets on Ubuntu

Want to see what targets are available on your system? This shows all targets, not just the one you are currently using.

bash
LinuxTeck.com
systemctl list-units --type=target --all
OUTPUT
UNIT LOAD ACTIVE SUB DESCRIPTION
basic.target loaded active active Basic System
cryptsetup.target loaded active active Local Encrypted Volumes
graphical.target loaded active active Graphical Interface
multi-user.target loaded active active Multi-User System
network-online.target loaded active active Network is Online
network.target loaded active active Network
rescue.target loaded inactive dead Rescue Mode
emergency.target loaded inactive dead Emergency Mode Boot

List All Available Boot Targets on Rocky Linux

Same command works on Rocky. The targets available might vary slightly depending on what packages are installed, but the core targets are consistent.

bash
LinuxTeck.com
systemctl list-units --type=target --all
OUTPUT
UNIT LOAD ACTIVE SUB DESCRIPTION
basic.target loaded active active Basic System
cryptsetup.target loaded active active Local Encrypted Volumes
graphical.target loaded active active Graphical Interface
multi-user.target loaded active active Multi-User System
network.target loaded active active Network
rescue.target loaded inactive dead Rescue Mode
emergency.target loaded inactive dead Emergency Mode Boot

Change Default Boot Target on Ubuntu

Now the important part. You need your Ubuntu server to boot into multi-user mode instead of graphical. This is permanent and takes effect on the next reboot.

bash
LinuxTeck.com
sudo systemctl set-default multi-user.target
OUTPUT
Removed symlink /etc/systemd/system/default.target.
Created symlink /etc/systemd/system/default.target → /usr/lib/systemd/system/multi-user.target.

What just happened: systemd created a symlink from /etc/systemd/system/default.target pointing to multi-user.target. On boot, systemd reads that symlink and knows which target to load. This change persists across reboots.

Change Default Boot Target on Rocky Linux

Same command works, but on Rocky you might not need sudo if you are already root. The symlink gets created in the same location.

bash
LinuxTeck.com
sudo systemctl set-default multi-user.target
OUTPUT
Removed symlink /etc/systemd/system/default.target.
Created symlink /etc/systemd/system/default.target → /usr/lib/systemd/system/multi-user.target.

Check What Init Process Is Running (PID 1) on Ubuntu

Verify that systemd is your init system and see how the old runlevel command still works alongside modern systemctl.

bash
LinuxTeck.com
ps -p 1
ls -la /sbin/init
runlevel
OUTPUT
PID TTY STAT TIME COMMAND
1 ? Ss 0:02 /lib/systemd/systemd --system --deserialize 21
lrwxrwxrwx 1 root root 20 Apr 10 12:30 /sbin/init -> /lib/systemd/systemd
N 5

This shows systemd is PID 1 and /sbin/init is a symlink pointing to systemd. The runlevel command returns "N 5", meaning the previous runlevel was N (none, system just started) and the current is 5 (graphical.target translated to old runlevel format).

Check What Init Process Is Running on Rocky Linux

Rocky Linux uses the exact same systemd init system. The commands are identical.

bash
LinuxTeck.com
ps -p 1
ls -la /sbin/init
runlevel
OUTPUT
PID TTY STAT TIME COMMAND
1 ? Ss 0:03 /usr/lib/systemd/systemd --system --deserialize 21
lrwxrwxrwx 1 root root 20 Feb 14 08:45 /sbin/init -> /usr/lib/systemd/systemd
N 3

Rocky returns "N 3" because it defaults to multi-user.target, which maps to the old runlevel 3. Everything else is the same.

Use the Old Runlevel Command to Change Targets

For backwards compatibility, you can still use init instead of systemctl isolate. These do the same thing.

bash
LinuxTeck.com
sudo init 3
sudo runlevel
sudo systemctl get-default
OUTPUT
5 3
graphical.target

Running init 3 switches to multi-user.target without rebooting. The runlevel command shows the transition from 5 to 3. But systemctl get-default still shows graphical.target because init does not change the permanent default, only the current running target.

Verify Your Changes Without Rebooting

You do not want to reboot and discover something broke. Verify first by checking the symlink and confirming get-default shows your new target.

bash
LinuxTeck.com
ls -la /etc/systemd/system/default.target
systemctl get-default
OUTPUT
lrwxrwxrwx 1 root root 37 Jun 24 10:42 /etc/systemd/system/default.target -> /usr/lib/systemd/system/multi-user.target
multi-user.target

Systemd Targets Boot Modes Comparison: Full Target Breakdown

Here is the complete breakdown of every major boot target and what it loads. This table shows you exactly what services run in each mode and which one you should actually use.

Target Name Purpose Loaded Services Best For Verdict
emergency.target Minimal boot, root shell only Basic kernel, single root session Rescue when system will not boot Last Resort
rescue.target Single-user mode with networking Basic services, network, no multi-user Maintenance and troubleshooting Repair Work
multi-user.target Full system, no GUI All core services, networking, no display manager Production servers, headless systems Standard Server
graphical.target Full system with desktop All core services, display manager, desktop environment Workstations and desktop machines Desktop Only

Edge Case: Services That Depend on Specific Targets:

Some services have ConditionVirtualization= or other conditions that prevent them from starting in certain targets. For example, a service might say "only start if this is not a virtual machine." If you run that service and the condition fails, it silently does not start. Check the service status with systemctl status servicename to see if conditions are blocking it. This is particularly common with hardware monitoring daemons that refuse to run in containers.

Hardening Tip: Control Rescue Mode Access:

By default, physical console access allows a user to reboot a system and manipulate the bootloader (GRUB) to enter single-user or rescue mode. For servers in secure data centers, you should ensure that local authentication is strictly enforced. While modern distributions utilize sulogin to natively force a root password prompt when entering rescue mode, you should verify security policies by checking drop-in configuration overrides under /etc/systemd/system/rescue.service.d/. This prevents unauthorized local root shell access during emergencies. Learn more about systemd security in the Linux Server Hardening Checklist.

Red Flags: What Breaks and How to Fix It

When boot targets go wrong, they fail silently. Services do not start, applications do not load, and you have no idea why until you dig into the logs. Here are the most common failures and how to diagnose them.

Services Fail to Start After Boot:

You change the default target and reboot, but critical services like postgresql or nginx do not start. Check the journal with sudo journalctl -xe --no-pager to see what failed. Often the service depends on a target unit that is not loaded. For example, if a service requires network-online.target but you booted into rescue.target, networking might not be fully initialized. Look for "condition check failed" or "dependency failed" in the output. Also check systemctl status servicename directly to see why it was skipped. The answer is usually right there in the "Condition" field.

GUI Fails to Load or Display Manager Crashes:

You are on a desktop Ubuntu machine and graphical.target should load, but nothing appears. First, verify the target is set correctly with systemctl get-default. If it says graphical.target, check if the display manager service actually started: systemctl status gdm (for GNOME) or systemctl status sddm (for KDE). If it failed, check journalctl -u gdm -n 50 to see the actual error. Common causes: GPU drivers missing, X11 configuration broken, or conflicting display server (X11 vs Wayland). This is almost never a problem with the target itself, but with the services the target tries to load.

Boot Hangs or Stalls at Target Loading:

Boot gets stuck and never completes. This usually means a service in that target is hanging waiting for something. Press Ctrl+Alt+F2 to get to a text console (if available) and run systemctl status to see which service is stuck. Then run systemctl isolate rescue.target to switch targets without rebooting. Once in rescue mode, you can investigate the problematic service or revert the target change. Check the Linux Server Backup Solutions article to ensure you have a recovery strategy before making drastic changes.

Boot Targets - Frequently Asked Questions

Q1: Can I switch boot targets without rebooting?

Yes. Use sudo systemctl isolate graphical.target to switch to graphical mode right now, or sudo systemctl isolate multi-user.target to drop to command line. This changes the current target but does not change what boots next time. To change the permanent default, use systemctl set-default. Many admins use isolate for testing before making the permanent change. See the article on switching to systemd timers for more on temporary systemd changes.

Q2: What happens if I set a target that does not exist?

systemctl will warn you with an error message. It will not create a broken symlink. If you accidentally delete the multi-user.target file itself (which is unlikely), systemd can still boot because the basic.target exists and contains the core functionality. Worst case, you end up in emergency.target. Reinstalling the systemd package restores missing target files. This is why you should always test with isolate before setting a target permanently.

Q3: Why does my Rocky Linux server boot slower than Ubuntu with the same hardware?

Often because of extra services enabled by default. Check which services are enabled: systemctl list-unit-files --state=enabled. Rocky and RHEL often enable SELinux, firewalld, and other security services that add startup time. Ubuntu is leaner by default. You can disable non-essential services with sudo systemctl disable servicename, but be careful not to disable anything you actually need. Check Linux System Administration Guide for more on service management.

Q4: Can I create my own custom boot target?

Yes, you can. Create a file like /etc/systemd/system/mycustom.target and use Requires= or Wants= directives to pull in specific services. But in practice, you rarely need to. The built-in targets cover 99% of use cases. If you find yourself creating custom targets, you are probably overcomplicating things. Use the standard multi-user.target or graphical.target and enable or disable specific services instead. This is cleaner and easier to maintain.


Final Thoughts: Choosing Your Boot Target

The rule is simple: servers use multi-user.target, desktops use graphical.target. Do not overthink it. Most production servers fail because someone either set the wrong target and forgot to change it back, or a service has an undeclared dependency on a feature only available in one target.

After you change the target, verify with get-default and test your critical services. If you are changing production systems, test in rescue mode first with isolate. Keep your SSH running and do not trust that a reboot will work until you have actually rebooted once in a staging environment.

For deeper understanding of how services interact with targets, read about bash scripting and automation and check your system logs regularly with Linux logging best practices. The more you understand your service dependencies, the fewer surprises you will have at boot time.

Further Reading on LinuxTeck:

Linux Commands for Beginners - Start here if you are new to the terminal and need confidence with basic commands.

Bash If Statement Complete Guide - Learn conditional logic for scripting service checks and startup automation.

Install LAMP Stack on Rocky Linux 9 - Practical walkthrough where boot targets matter for web server deployment.

PS Command in Linux with Examples - Monitor running processes and verify your services loaded in the target you chose.

LinuxTeck - A Complete Linux Infrastructure Blog

LinuxTeck covers everything from beginner Linux commands to advanced Linux system administration and DevOps career guidance, written by practitioners for professionals working on Ubuntu, Rocky Linux, RHEL, and enterprise Linux environments every day.

About Aneeshya S

Aneeshya S is a Senior Linux Trainer and System Administrator with over 10 years of experience. She actively follows emerging technologies and industry trends. Outside the terminal, she enjoys music and travel.

View all posts by Aneeshya S →

Leave a Reply

Your email address will not be published.

L