Step-by-Step Guide to Writing Custom systemd Unit Files

Creating Custom Unit Files in systemd

Creating Custom Unit Files in systemd

Systemd unit files give you the power to define, control, and manage background services on a Linux system. Whether you're building your own script-based service or integrating a third-party executable, creating a custom unit file ensures it behaves just the way you want it to. This guide walks you through the process step-by-step—from preparing your executable to activating your service in the systemd ecosystem.

Step 1: Prepare Your Executable

Every custom service begins with an executable — this could be a compiled binary or a script that performs a defined task. Think of this as the “engine” your systemd unit will start, stop, and monitor.

Example: Suppose you have a simple shell script that backs up a directory every night. You might write something like this:

#!/bin/bash
tar -czf /var/backups/home_backup_$(date +%F).tar.gz /home/myuser/

Save this as /usr/local/bin/backup.sh and make it executable:

# chmod a+x /usr/local/bin/backup.sh

PID File (Optional): If your script launches a long-running process (like a background server), you might want to create a PID file. This file stores the process ID (PID) of the main running service, allowing systemd to monitor or restart it properly.

Example: A custom server script might create a PID file like this:

#!/bin/bash
echo $$ > /var/run/myserver.pid
exec /usr/local/bin/myserver-binary

Using Environment Files: If your script relies on environment variables—like credentials, paths, or configuration flags—it's cleaner to keep them in a separate file.

# /etc/myservice.env
BACKUP_SOURCE=/home/myuser
BACKUP_DEST=/var/backups

Then in your systemd service definition, you can link this file using the EnvironmentFile= directive:

EnvironmentFile=/etc/myservice.env

Important: Make sure your executable runs independently without asking for user input. Services should start and operate silently in the background. Any script that requires keyboard interaction (e.g., password prompts or confirmations) is not suitable for systemd automation.

Step 2: Create the Unit File

Once your executable script or binary is ready, the next step is to define how systemd should interact with it. This is done through a unit file.

Systemd looks for custom services in /etc/systemd/system/. This is the preferred location for services created by system administrators, as it overrides any vendor-supplied definitions from /lib/systemd/system.

Let’s continue with the earlier example: if your script is a backup tool, you could name your service daily-backup.service.

# touch /etc/systemd/system/daily-backup.service
# chmod 644 /etc/systemd/system/daily-backup.service

The first command creates an empty service file, while the second sets read/write access for the owner (root) and read-only access for everyone else.

Note: Unit files are configuration files—they are not meant to be executed directly. This is why you don’t set executable permissions on them.

Step 3: Define the Service Configuration

Now that the unit file is created, it's time to tell systemd how to run your service. You do this by editing the file and adding specific sections: [Unit], [Service], and [Install].

Here’s a practical example for our backup script:

[Unit]
Description=Nightly Backup Service
After=network.target

[Service]
ExecStart=/usr/local/bin/backup.sh
Type=oneshot
RemainAfterExit=true
EnvironmentFile=/etc/myservice.env

[Install]
WantedBy=multi-user.target
  • Description: A short label that shows up in logs and status checks to describe your service.
  • After=network.target: Ensures your script runs only after the network is initialized—useful for services that depend on internet or file sharing.
  • ExecStart: The full path to the executable or script systemd will run.
  • Type=oneshot: Ideal for scripts that run a task and exit immediately (like backups). Use forking for background daemons.
  • RemainAfterExit=true: Keeps the service in “active” state even after the script exits—useful for tracking.
  • EnvironmentFile: Points to the file that holds environment variables needed by the script.
  • WantedBy=multi-user.target: Defines when the service should start if enabled. This target resembles runlevel 3 in classic init systems.

Tip: For long-running services, change Type to forking and add a PIDFile line if your service creates one.

Step 4: Activate and Start the Service

With your service fully defined, it’s time to bring it to life. But before you can start it, you need to reload systemd so it reads your new unit file.

# systemctl daemon-reload
# systemctl start daily-backup.service

Make sure to substitute daily-backup.service with whatever name you used for your own unit file.

Want it to start automatically at boot time? Run:

# systemctl enable daily-backup.service

This creates the appropriate symlinks to ensure systemd starts the service during system initialization.

Important Note

Comments

Popular Posts

Puppet Code Deploy Troubleshooting & Resolution Guide

Fix: SSH Permission Denied Issue | Real Solution

Linux Process Termination Signals Explained with Examples