Amblem
Furkan Baytekin

From Script to Service: Writing Custom Systemd Units in Linux

Convert Linux scripts to systemd services

From Script to Service: Writing Custom Systemd Units in Linux
54
5 minutes

Systemd is the backbone of most modern Linux distributions, managing services, daemons, and system resources with precision. Writing custom systemd units allows you to transform scripts into reliable, manageable services. In this guide, we’ll walk through creating custom systemd units, complete with real-world examples, to help you automate and manage your Linux tasks effectively. Whether you’re running a web server or a custom Python script, this post will make the process clear, SEO-friendly, and beginner-friendly.

What is a Systemd Unit?

Systemd units are configuration files that define how services, sockets, timers, and other resources behave. For this post, we’ll focus on service units, which manage daemons or scripts as services. These files, ending in .service, live in /etc/systemd/system/ (for custom units) or /lib/systemd/system/ (for system-provided units).

By creating a custom systemd unit, you can:

Let’s dive into crafting a custom systemd unit with practical examples.

Why Use Custom Systemd Units?

Custom systemd units bring structure to your scripts. Instead of manually running a Python script or server process, a systemd unit lets you:

This is especially useful for developers and sysadmins managing web apps, cron-like tasks, or background workers.

Step-by-Step: Writing a Custom Systemd Unit

Let’s create a systemd unit for a real-world example: a Python web server using Flask. We’ll then extend it to a more complex case, like a background worker.

Step 1: Write Your Script

First, create a simple Flask app. Save this as /home/user/myapp/app.py:

python
from flask import Flask app = Flask(__name__) @app.route('/') def hello(): return "Hello from my Flask app!" if __name__ == "__main__": app.run(host="0.0.0.0", port=8080)

This script runs a web server on port 8080. Without systemd, you’d need to run it manually (python3 app.py), and it wouldn’t restart if it crashes.

Step 2: Create the Systemd Unit File

Create a file named /etc/systemd/system/myapp.service. Here’s a basic systemd unit for the Flask app:

ini
[Unit] Description=My Flask Web App After=network.target [Service] ExecStart=/usr/bin/python3 /home/user/myapp/app.py WorkingDirectory=/home/user/myapp Restart=always User=user Environment="PYTHONUNBUFFERED=1" [Install] WantedBy=multi-user.target

Let’s break down the key directives:

Step 3: Enable and Start the Service

After creating the unit file, run these commands:

  1. Reload systemd to recognize the new unit:

    bash
    sudo systemctl daemon-reload
  2. Enable the service to start at boot:

    bash
    sudo systemctl enable myapp.service
  3. Start the service:

    bash
    sudo systemctl start myapp.service
  4. Check the status:

    bash
    sudo systemctl status myapp.service

You should see output confirming the service is running. Access http://your-server-ip:8080 to verify the Flask app is live.

Step 4: Monitor and Debug

Use journalctl to view logs:

bash
journalctl -u myapp.service

This shows output from your Flask app, helping you debug issues like crashes or misconfigurations.

Real-World Example: Background Worker

Let’s try a more complex case: a Python script that processes tasks in the background. Save this as /home/user/worker/worker.py:

python
import time while True: print("Processing task...") time.sleep(10)

Create a systemd unit at /etc/systemd/system/worker.service:

ini
[Unit] Description=My Background Worker After=network.target [Service] ExecStart=/usr/bin/python3 /home/user/worker/worker.py WorkingDirectory=/home/user/worker Restart=on-failure User=user Environment="PYTHONUNBUFFERED=1" StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target

Key differences:

Run the same systemctl commands to enable and start the service. Check logs with:

bash
journalctl -u worker.service -f

Advanced Tips for Systemd Units

Example timer for running a script daily (/etc/systemd/system/daily-task.timer):

ini
[Unit] Description=Run daily task [Timer] OnCalendar=daily Persistent=true [Install] WantedBy=timers.target

Pair it with a service unit to execute the task.

Common Pitfalls and Fixes

Conclusion

Writing custom systemd units is a game-changer for Linux automation. By turning scripts into services, you gain control, reliability, and seamless integration with systemd’s ecosystem. Whether it’s a Flask web app or a background worker, the process is straightforward: write your script, create a .service file, and manage it with systemctl.


Album of the day:

Suggested Blog Posts