Linux

Creating a systemd Service in Linux: A Complete Step-by-Step Guide

This guide explains in detail how to create your own system daemon in Linux using systemd. You'll learn to write unit files, manage services (start/stop/status), configure autostart, and handle logging.

Updated at February 15, 2026
15-20 min
Medium
FixPedia Team
Применимо к:systemd (Ubuntu 22.04+, Debian 11+, CentOS 8+, RHEL 8+, Fedora 35+)Linux with systemd

Introduction / Why This Is Needed

Systemd is a modern init system and service manager for most Linux distributions. Creating your own service (daemon) allows you to automatically run your scripts or programs at system boot, manage their lifecycle (start, stop, restart), centralize logging output, and ensure recovery from failures. This is the standard and reliable way to deploy background tasks in Linux.

After completing this guide, you will be able to create a working service for any executable program (Python script, bash script, binary file) that will:

  • Automatically start when the OS boots.
  • Shut down gracefully on system shutdown.
  • Write logs to journald (the system journal).
  • Restart after a crash.

Requirements / Preparation

Before you begin, ensure that:

  1. You have terminal access with sudo privileges (for system services) or access to your home directory (for user services).
  2. Systemd is installed on your system (relevant for all modern distributions: Ubuntu 22.04+, Debian 11+, CentOS 8/RHEL 8+, Fedora 35+).
  3. The executable file or script you want to service is already prepared, manually tested, and has execute permissions (chmod +x /path/to/file).
  4. You know the absolute path to this executable file.

Step 1: Preparing the Executable Script or Program

Assume you have a simple bash script for monitoring disk space that should run in the background. It is already created and located at /opt/scripts/disk_monitor.sh.

#!/bin/bash
# Example script /opt/scripts/disk_monitor.sh
while true; do
    DATE=$(date '+%Y-%m-%d %H:%M:%S')
    df -h / | tail -n1 | awk '{print "ROOT: " $5 " used"}' >> /var/log/disk_monitor.log
    sleep 300
done

Test it manually:

sudo chmod +x /opt/scripts/disk_monitor.sh
sudo /opt/scripts/disk_monitor.sh

Press Ctrl+C to stop it for testing. Ensure entries appear in /var/log/disk_monitor.log.

Step 2: Creating the Unit File

Create the service file. For a system service (running as root or a specified user), use /etc/systemd/system/.

sudo nano /etc/systemd/system/disk-monitor.service

💡 Tip: The filename usually matches the service name. Use lowercase letters, numbers, and hyphens. A dot in the name is not required but permissible.

Step 3: Writing the Basic Unit and Service Configuration

Paste the following configuration into the editor. It covers most basic scenarios.

[Unit]
Description=Service for monitoring free space on the root partition
Documentation=man:df(1)
After=network.target

[Service]
Type=simple
ExecStart=/opt/scripts/disk_monitor.sh
Restart=on-failure
RestartSec=10
User=root
Group=root

[Install]
WantedBy=multi-user.target

Section Breakdown:

  • [Unit] — metadata and dependencies.
    • Description — a brief description of the service (shown in systemctl status).
    • After — indicates the service should start after the network is up (network.target). For non-network services, you can remove this or specify local-fs.target (after local filesystems are mounted).
  • [Service] — main process configuration.
    • Type=simple (default) — systemd assumes the process specified in ExecStart is the main one and runs in the foreground. Suitable for most scripts and modern programs.
    • ExecStart — the absolute path to the command/script to run. All arguments are specified here.
    • Restart=on-failure — automatically restart the service if it exits with a non-zero return code.
    • RestartSec=10 — wait 10 seconds before restarting.
    • User/Group — the user/group to run the process as. It is safer to specify a non-root user (e.g., User=monitoruser) unless root privileges are necessary. For system utilities, root may be required.
  • [Install] — instructions for systemctl enable.
    • WantedBy=multi-user.target — creates a symlink in /etc/systemd/system/multi-user.target.wants/, meaning "start at boot in multi-user mode (standard)." For graphical services, graphical.target may be used.

Save the file (Ctrl+O, Enter) and exit the editor (Ctrl+X).

Step 4: Configuring Autostart and Initialization

After creating or modifying a unit file, you must reload the systemd configuration:

sudo systemctl daemon-reload

Now enable the service for autostart (creates the symlink):

sudo systemctl enable disk-monitor.service

Output: Created symlink /etc/systemd/system/multi-user.target.wants/disk-monitor.service → /etc/systemd/system/disk-monitor.service.

Step 5: Starting and Checking Status

Start the service manually:

sudo systemctl start disk-monitor.service

Check its status:

sudo systemctl status disk-monitor.service

Expected output (simplified):

● disk-monitor.service - Service for monitoring free space on the root partition
   Loaded: loaded (/etc/systemd/system/disk-monitor.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2026-02-15 14:30:00 MSK; 5s ago
 Main PID: 12345 (bash)
    Tasks: 1 (limit: 4915)
   Memory: 1.2M
   CGroup: /system.slice/disk-monitor.service
           └─12345 /bin/bash /opt/scripts/disk_monitor.sh

Key lines:

  • Loaded — file is loaded, enabled — enabled for autostart.
  • Active: active (running) — service is running.
  • Main PID — PID of the main process.
  • CGroup — the cgroup the process is placed in.

Step N: Additional Management Operations

You can now manage the service with standard commands:

  • Stop: sudo systemctl stop disk-monitor.service
  • Restart: sudo systemctl restart disk-monitor.service (use if you changed the config).
  • Reload: sudo systemctl reload disk-monitor.service (if the service supports SIGHUP to reload config without full stop).
  • View logs: sudo journalctl -u disk-monitor.service -f (-f — follow new entries in real time).
  • Check configuration syntax: sudo systemctl daemon-reload (runs automatically on enable/start, but useful after manual file edits).

Verifying the Result

  1. Autostart: Reboot the system (sudo reboot). After logging in, check the service status: systemctl status disk-monitor.service. It should be active (running).
  2. Logging: Ensure logs are being written: sudo tail -f /var/log/disk_monitor.log or via journald: sudo journalctl -u disk-monitor.service.
  3. Automatic recovery: Forcefully terminate the process (e.g., sudo kill <PID> from the status output). Check the status again after a few seconds — systemd should have restarted it.

Common Issues

Issue: systemctl status shows failed (Result: exit-code). Solution: Check the error details in the same status output (the ... line). Most often this is:

  • Incorrect path in ExecStart. Ensure the path is absolute and the file exists.
  • Missing execute permissions. sudo chmod +x /path/to/script.
  • Error inside the script. Run the script manually as the same user (sudo -u <user> /path/to/script) and check the output.
  • Dependencies. If the script needs network or mounted disks, check After= and Requires= in the [Unit] section.

Issue: Service is not enabled for autostart (systemctl is-enabled returns disabled). Solution: Run sudo systemctl enable disk-monitor.service again after daemon-reload. Ensure the [Install] section has WantedBy= or RequiredBy=.

Issue: Service logs are empty in journalctl. Solution: By default, systemd captures stdout/stderr. If the script writes directly to a file (as in the example), its output won't appear in journald. This is normal. For journald logging, remove the file redirection from the script and configure log rotation with journalctl, or use StandardOutput=append:/var/log/disk_monitor.log in the [Service] section.

Issue: Service starts but immediately exits. Solution: This often happens with Type=simple if the main process exits. For long-running scripts, ensure they have an infinite loop or wait (sleep). If the program daemonizes itself (forks), you may need Type=forking and PIDFile=/var/run/name.pid. But for simple scripts with a loop, Type=simple is the correct choice.

F.A.Q.

Where should custom unit files be placed?
Why doesn't my service start after creation?
How to create a service that runs as a specific user instead of root?
What is `Type=forking` and when is it needed?

Hints

Preparing the executable script or program
Creating the unit file
Writing the basic [Unit] and [Service] configuration
Configuring autostart and initialization
Starting and checking status
FixPedia

Free encyclopedia for fixing errors. Step-by-step guides for Windows, Linux, macOS and more.

© 2026 FixPedia. All materials are available for free.

Made with for the community