Step-by-Step Guide to Writing Custom systemd Unit Files
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.
Comments
Post a Comment