systemctl is the primary command-line tool for interacting with systemd, the init system and service manager used by virtually every modern Linux distribution โ including Ubuntu, Debian, Fedora, AlmaLinux, Rocky Linux, CentOS Stream, openSUSE, and Arch Linux. Whether you're managing services, controlling the boot process, scheduling tasks with timers, or troubleshooting a failed daemon, systemctl is the command you'll reach for dozens of times a day.
In this comprehensive guide, you'll learn every essential systemctl command โ from starting and stopping services to writing production-ready unit files, creating systemd timers as a replacement for cron, analyzing boot performance, and troubleshooting failed services. By the end of this article, you'll have the complete toolkit of a professional Linux system administrator.
What Is systemd and Why Does It Matter?
systemd is a suite of system components for Linux that replaces the older SysV init system. It provides parallel service startup for faster boot times, on-demand daemon activation via sockets, dependency-based service control, integrated logging through journalctl, and powerful scheduling with systemd timers.
systemctl is the main command used to introspect and control the state of systemd and its managed "units" โ services, sockets, targets, timers, mounts, and more. Understanding systemctl is non-negotiable for anyone running Linux servers in production.
Service Management Basics: Start, Stop, Restart, Reload
The most common daily tasks for any Linux administrator involve starting, stopping, and restarting services. Here are the fundamental systemctl commands you need to know:
# Start a service immediately
sudo systemctl start nginx
# Stop a running service
sudo systemctl stop nginx
# Restart a service (fully stops then starts)
sudo systemctl restart nginx
# Reload configuration without downtime (if the service supports it)
sudo systemctl reload nginx
# Reload if supported, otherwise restart
sudo systemctl reload-or-restart nginx
# View detailed service status including recent logs
systemctl status nginx
# Enable a service to start automatically at boot
sudo systemctl enable nginx
# Disable a service from starting at boot
sudo systemctl disable nginx
# Enable AND start the service in a single command
sudo systemctl enable --now nginx
# Disable AND stop the service in a single command
sudo systemctl disable --now nginx
Pro tip: Always prefer reload over restart when possible for production web servers like Nginx and Apache โ it applies new configuration without dropping active connections, enabling true zero-downtime deployments.
Checking Service Status and Listing Units
Knowing how to quickly check the state of services is critical during incidents and routine health checks. systemctl provides both human-readable and script-friendly ways to query status:
# Full detailed status with the last 10 log lines
systemctl status nginx
# Quick boolean checks โ ideal for shell scripts and monitoring
systemctl is-active nginx # Returns "active" or "inactive"
systemctl is-enabled nginx # Returns "enabled" or "disabled"
systemctl is-failed nginx # Returns "failed" or "active"
# List all currently loaded services
systemctl list-units --type=service
# List only services that are actively running
systemctl list-units --type=service --state=running
# List every service that is enabled to start at boot
systemctl list-unit-files --type=service --state=enabled
# Show ALL failed services โ your first stop when troubleshooting
systemctl --failed
# Show what a service depends on
systemctl list-dependencies nginx
# Show what depends ON a service (reverse dependency tree)
systemctl list-dependencies --reverse nginx
Using is-active, is-enabled, and is-failed in shell scripts allows you to build lightweight monitoring and automation without needing external tools.
Creating Custom systemd Service Unit Files
One of systemd's most powerful features is the ability to turn any script, binary, or application into a fully managed service with automatic restart, logging, security hardening, and boot integration. Custom unit files live in /etc/systemd/system/.
# Display an existing unit file
systemctl cat nginx.service
# Show the full file path of the unit
systemctl show -p FragmentPath nginx.service
# Create a new custom service
sudo nano /etc/systemd/system/myapp.service
Production Example: Node.js Application Service
The following is a production-grade unit file for a Node.js application, complete with security hardening options:
[Unit]
Description=My Node.js Application
Documentation=https://docs.myapp.com
After=network.target postgresql.service
Requires=postgresql.service
[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/var/www/myapp
ExecStart=/usr/bin/node server.js
ExecReload=/bin/kill -HUP $MAINPID
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
Environment=NODE_ENV=production
Environment=PORT=3000
EnvironmentFile=/var/www/myapp/.env
# Security hardening options
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/var/www/myapp/data /var/www/myapp/logs
PrivateTmp=yes
ProtectKernelTunables=yes
[Install]
WantedBy=multi-user.target
Production Example: Python Flask Application with Gunicorn
[Unit]
Description=Flask Web Application
After=network.target
[Service]
Type=simple
User=flask
WorkingDirectory=/var/www/flask-app
ExecStart=/var/www/flask-app/venv/bin/gunicorn -w 4 -b 0.0.0.0:8000 app:app
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
After creating or modifying any unit file, you must reload the systemd daemon before the changes take effect:
# Reload systemd to recognize new or changed unit files
sudo systemctl daemon-reload
# Enable and start your new service
sudo systemctl enable --now myapp.service
# Verify everything is working
systemctl status myapp.service
Editing and Overriding Existing Unit Files
When you need to tweak a distribution-provided service (like nginx or postgresql), never edit the original unit file directly โ package updates will overwrite your changes. Instead, use drop-in override files, which layer your customizations on top of the original:
# Create a drop-in override (recommended approach)
sudo systemctl edit nginx.service
# This creates /etc/systemd/system/nginx.service.d/override.conf
# Example override content:
# [Service]
# RestartSec=10
# TimeoutStartSec=90
# Edit the FULL unit file (copies and replaces the entire original)
sudo systemctl edit --full nginx.service
# Always reload after editing
sudo systemctl daemon-reload
journalctl: Reading and Managing systemd Logs
systemd centralizes all service logs in its journal, accessible via the journalctl command. This eliminates the need to hunt through separate log files in /var/log/ and provides powerful filtering by time, priority, boot, and service.
# View ALL system logs
journalctl
# Show logs for a specific service
journalctl -u nginx
# Only today's logs
journalctl -u nginx --since today
# Logs from a specific time range
journalctl -u nginx --since "2026-04-11 08:00" --until "2026-04-11 12:00"
# Logs from the last hour
journalctl -u nginx --since "1 hour ago"
# Follow logs in real-time (like tail -f)
journalctl -u nginx -f
# Show only errors and more severe messages
journalctl -u nginx -p err
# Priority levels: emerg, alert, crit, err, warning, notice, info, debug
journalctl -p warning..err # Filter by priority range
# Show only kernel messages
journalctl -k
# Logs from the current boot only
journalctl -b
# Logs from the previous boot
journalctl -b -1
# List every boot recorded in the journal
journalctl --list-boots
# Output logs as JSON (great for parsing with jq)
journalctl -u nginx -o json-pretty
# Show only the last 50 lines
journalctl -u nginx -n 50
# Disable the pager (dump directly to stdout)
journalctl -u nginx --no-pager
# Check how much disk space the journal is using
journalctl --disk-usage
# Clean up old journal entries
sudo journalctl --vacuum-size=500M
sudo journalctl --vacuum-time=30d
systemd Timers: The Modern Replacement for Cron
systemd timers offer several advantages over traditional cron: they integrate with journalctl for logging, support dependencies on other units, can catch up on missed runs after downtime (Persistent=true), and allow randomized delays to prevent thundering-herd problems.
# List all active timers with their next scheduled run
systemctl list-timers
# Include inactive timers as well
systemctl list-timers --all
Example: Creating a Daily Database Backup Timer
Step 1: Create the service at /etc/systemd/system/backup.service:
[Unit]
Description=Daily Database Backup
[Service]
Type=oneshot
ExecStart=/opt/scripts/backup.sh
User=backup
Step 2: Create the timer at /etc/systemd/system/backup.timer:
[Unit]
Description=Daily Backup Timer
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
RandomizedDelaySec=300
[Install]
WantedBy=timers.target
Step 3: Enable and start the timer:
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
systemctl status backup.timer
Common OnCalendar Expressions
OnCalendar=hourly # Every hour
OnCalendar=daily # Every day at midnight
OnCalendar=weekly # Every Monday at midnight
OnCalendar=*-*-* 06:00:00 # Daily at 6 AM
OnCalendar=Mon *-*-* 09:00:00 # Every Monday at 9 AM
OnCalendar=*-*-01 03:00:00 # First day of every month at 3 AM
System Power and Boot Target Management
systemctl also controls power states and runlevels (called "targets" in systemd terminology):
# Reboot the system
sudo systemctl reboot
# Shut down and power off
sudo systemctl poweroff
# Suspend to RAM
sudo systemctl suspend
# Hibernate to disk
sudo systemctl hibernate
# Enter rescue (single-user) mode
sudo systemctl rescue
# Check the current default boot target
systemctl get-default
# Set the default boot target
sudo systemctl set-default multi-user.target # Server mode โ no GUI
sudo systemctl set-default graphical.target # Desktop mode โ with GUI
# Switch to a different target without rebooting
sudo systemctl isolate multi-user.target
Masking Services and Analyzing Boot Performance
Masking is a stronger form of disabling โ it makes a service impossible to start, even manually or as a dependency of another service. This is useful for permanently blocking conflicting services.
# Mask a service โ completely prevents it from starting
sudo systemctl mask nginx
# This creates a symlink from the unit file to /dev/null
# Undo masking
sudo systemctl unmask nginx
# Show the total boot time
systemd-analyze
# Rank services by how long they took to start (find bottlenecks)
systemd-analyze blame
# Show the critical chain of dependencies during boot
systemd-analyze critical-chain
# Generate a beautiful SVG visualization of the boot process
systemd-analyze plot > boot.svg
# Validate the syntax of a unit file before deploying
sudo systemd-analyze verify /etc/systemd/system/myapp.service
Troubleshooting Failed systemd Services: Step-by-Step
When a service won't start, follow this systematic troubleshooting workflow:
# Step 1: See which services have failed
systemctl --failed
# Step 2: Get detailed status and the last log lines
systemctl status myapp.service
# Step 3: Read full logs for the current boot
journalctl -u myapp.service -b --no-pager
# Step 4: Validate the unit file syntax
systemd-analyze verify /etc/systemd/system/myapp.service
# Step 5: Inspect every resolved property of the service
systemctl show myapp.service
# Step 6: After fixing the problem, clear the failed state
sudo systemctl reset-failed myapp.service
Common Causes of systemd Service Failures
- The
ExecStartpath does not exist or lacks execute permission - The specified
UserorGroupdoes not exist on the system - The
WorkingDirectorydoes not exist or is not accessible - The port the service wants to bind is already in use
- Required environment variables are missing from
EnvironmentFile - Permission denied errors on files, sockets, or directories
- Missing dependencies not listed in
After=orRequires= - SELinux or AppArmor denying the service access
Frequently Asked Questions About systemctl
What's the difference between systemctl enable and start?
start launches a service immediately but does not configure it to start at boot. enable configures a service to launch automatically at boot but does not start it right now. Use enable --now to do both in one command.
What's the difference between disable and mask?
disable only prevents automatic startup at boot โ the service can still be started manually or as a dependency. mask makes a service completely unstartable by any means until it is unmasked.
Do I need to run daemon-reload after every change?
Yes โ any time you create, edit, or delete a unit file in /etc/systemd/system/, you must run sudo systemctl daemon-reload before systemd will see the changes.
Are systemd timers better than cron?
For most modern use cases, yes. Timers integrate with journalctl logging, support dependencies between units, can catch up on missed runs after downtime, and allow randomized delays. Cron is still simpler for basic one-line jobs.
How can I see all available unit types?
Run systemctl --type=help to see every unit type systemd supports, including service, socket, timer, mount, target, path, and more.
Recommended Reading
Deepen your Linux administration skills with these in-depth guides:
- Linux System Administration Handbook
- Linux Administration Fundamentals
- Linux Troubleshooting Techniques
Conclusion
Mastering systemctl transforms how you manage Linux servers. From controlling services and writing hardened unit files, to reading logs with journalctl, scheduling jobs with timers, and diagnosing failures with systemd-analyze, these commands form the backbone of modern Linux system administration. Bookmark this guide, practice the examples on a test server, and systemd will quickly feel like second nature.
For a printable quick-reference with all 40+ commands in one page, download our systemctl Commands Cheat Sheet.