funwithlinux guide

How to Use Systemd Run Levels for Effective Control

In the world of Linux system administration, managing the state of your system—whether it’s booting into a graphical interface, a command-line-only environment, or troubleshooting a broken setup—relies heavily on understanding **run levels**. Traditionally, SysV init systems used numeric run levels (0-6) to define system states, but modern Linux distributions have adopted **systemd**, a more flexible and powerful init system. Systemd replaces run levels with **targets**, which are logical groups of services and units that define the system’s operational state. Mastering systemd targets (the modern equivalent of run levels) is critical for controlling your system’s behavior, optimizing resource usage, and troubleshooting issues. This guide will demystify systemd targets, explain how they map to traditional run levels, and walk you through practical tasks like viewing, changing, and managing targets for effective system control.

Table of Contents

  1. Understanding Run Levels and Systemd Targets
  2. Systemd Targets vs. Traditional Runlevels: Key Differences
  3. Common Systemd Targets Explained
  4. How to View the Current Target
  5. Changing Targets: Temporarily and Permanently
  6. Managing Services Across Targets
  7. Troubleshooting with Targets
  8. Best Practices for Using Systemd Targets
  9. Conclusion
  10. References

1. Understanding Run Levels and Systemd Targets

What Are Run Levels?

Run levels are predefined states that a Linux system can operate in, determining which services (e.g., network, graphical interface, SSH) are active. For example, a server might run in a “multi-user command-line” run level, while a desktop might use a “graphical” run level.

Systemd Targets: The Modern Evolution

Systemd, introduced in 2010, replaced SysV init and reimagined run levels as targets. A target is a unit file (.target) that groups other systemd units (services, sockets, mounts) to define a system state. Unlike rigid numeric run levels, targets are modular: multiple targets can be active simultaneously, and they can depend on other targets (e.g., graphical.target depends on multi-user.target, which in turn depends on basic.target).

2. Systemd Targets vs. Traditional Runlevels: Key Differences

Traditional SysV runlevels use numbers (0-6), while systemd targets use descriptive names. Here’s how they map, along with key differences:

Traditional RunlevelSystemd TargetPurpose
0poweroff.targetShut down the system.
1rescue.targetSingle-user mode for troubleshooting.
2multi-user.targetMulti-user, no graphical interface (varies by distro).
3multi-user.targetMulti-user, command-line only (most common for servers).
4multi-user.targetUnused by default (customizable).
5graphical.targetMulti-user with graphical interface (desktops).
6reboot.targetReboot the system.

Key Advantages of Targets:

  • Flexibility: Targets can include or depend on other targets (e.g., graphical.target requires multi-user.target).
  • Parallelism: Systemd starts targets and their dependencies in parallel, speeding up boot time.
  • Explicitness: Names like rescue.target are more intuitive than numeric runlevels.

3. Common Systemd Targets Explained

Beyond the runlevel mappings, systemd includes many specialized targets. Here are the most useful ones:

  • emergency.target: Minimal state with only the root filesystem mounted (read-only). No networking or services—use for critical repairs (e.g., corrupted fstab).
  • rescue.target: Single-user mode with basic services (networking may be disabled). Use for troubleshooting (e.g., failed service preventing boot).
  • basic.target: Loads essential services (e.g., udev, mounts) and forms the base for higher targets.
  • multi-user.target: Multi-user mode with networking, SSH, and command-line access (default for servers).
  • graphical.target: Multi-user mode with a graphical desktop (default for desktops/laptops).
  • shutdown.target: Intermediate target for shutting down (used by poweroff.target).

4. How to View the Current Target

To control targets, you first need to know which are active or set as default. Use these commands:

View the Default Target (Boot Target)

The default target is what the system boots into. Check it with:

systemctl get-default

Example Output:

multi-user.target  # Default for servers  
# OR  
graphical.target   # Default for desktops  

View Active Targets

To see all currently active targets (systemd can have multiple active targets), run:

systemctl list-units --type=target --state=active

Example 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
  graphical.target       loaded active active Graphical Interface
  local-fs.target        loaded active active Local File Systems
  multi-user.target      loaded active active Multi-User System
  network.target         loaded active active Network
  ...  

5. Changing Targets: Temporarily and Permanently

You can switch targets temporarily (for the current session) or permanently (persist across reboots).

Temporarily Switch Targets: systemctl isolate

Use systemctl isolate <target> to activate a target and stop all units not required by it. This is like “switching runlevels” temporarily.

Examples:

  • Switch to graphical mode (from command line):
    sudo systemctl isolate graphical.target
  • Switch to command-line mode (from GUI):
    sudo systemctl isolate multi-user.target  # Closes the GUI, keeps networking
  • Enter rescue mode:
    sudo systemctl isolate rescue.target

Warning: isolate stops non-essential services. Avoid using it with poweroff.target or reboot.target unless you intend to shut down/reboot immediately.

Permanently Change the Default Target: systemctl set-default

To change the target the system boots into, use systemctl set-default <target>.

Examples:

  • Set servers to boot into command-line mode:
    sudo systemctl set-default multi-user.target
  • Set desktops to boot into GUI:
    sudo systemctl set-default graphical.target

Verify the change:

systemctl get-default  # Should show the new target

6. Managing Services Across Targets

Targets control which services start at boot. To ensure a service runs in a specific target (e.g., nginx on multi-user.target), use these techniques:

Enable a Service for a Target

By default, enabling a service with systemctl enable <service> links it to the default target. To enable it for a specific target, use:

sudo systemctl enable --now <service>@<target>.target
  • --now: Starts the service immediately (optional).

Example: Enable ssh.service for multi-user.target (ensures SSH starts on server boot):

sudo systemctl enable --now [email protected]

Modify a Service’s Target Dependencies

Services define their target dependencies in their unit files (e.g., /etc/systemd/system/myapp.service). The [Install] section specifies which targets the service should be enabled for:

[Unit]
Description=My Custom App

[Service]
ExecStart=/usr/local/bin/myapp

[Install]
WantedBy=multi-user.target  # Start when multi-user.target is active

After editing, reload systemd and enable the service:

sudo systemctl daemon-reload
sudo systemctl enable myapp.service

7. Troubleshooting with Targets

Targets are invaluable for fixing unbootable systems or misbehaving services. Here are common scenarios:

Scenario 1: System Fails to Boot (Stuck at Login/Black Screen)

If a failed service (e.g., gdm for desktops) prevents boot, boot into rescue.target:

  1. At the GRUB menu, press e to edit the kernel command line.
  2. Find the line starting with linux (e.g., linux /boot/vmlinuz-... root=...).
  3. Add systemd.unit=rescue.target to the end of this line.
  4. Press Ctrl+X to boot into rescue mode.
  5. Log in as root, then check for errors:
    journalctl -b -p err  # Show errors from the current boot (-b)
  6. Disable the problematic service (e.g., gdm):
    systemctl disable gdm.service
  7. Reboot:
    reboot

Scenario 2: Corrupted Filesystem (e.g., fstab Errors)

Use emergency.target for read-only root access:

  1. At GRUB, edit the kernel line and add systemd.unit=emergency.target.
  2. Boot, then remount the root filesystem as read-write:
    mount -o remount,rw /
  3. Fix the corrupted file (e.g., nano /etc/fstab).
  4. Reboot:
    reboot

8. Best Practices for Using Systemd Targets

To avoid pitfalls, follow these guidelines:

  • Stick to Defaults Unless Necessary: Only change the default target if your use case requires it (e.g., servers → multi-user.target).
  • Test Changes in a VM: Always test target switches or service modifications in a virtual machine before applying to production.
  • Use isolate Cautiously: systemctl isolate stops non-essential services—avoid it on production systems unless you’re certain (e.g., no active users).
  • Document Changes: Log target modifications (e.g., “Set multi-user.target as default for server X on 2024-03-15”) for troubleshooting.
  • Leverage is-active for Checks: Verify a target is active with:
    systemctl is-active graphical.target  # Output: active/inactive

9. Conclusion

Systemd targets replace traditional runlevels with a flexible, modular system for controlling your Linux environment. By mastering targets, you can boot into specific states, manage services efficiently, and troubleshoot critical issues. Whether you’re a server admin or desktop user, understanding multi-user.target, rescue.target, and how to switch between them is essential for effective system control.

Start small: experiment with systemctl isolate in a VM, then move to modifying default targets. With practice, you’ll wield systemd targets like a pro.

10. References