DEV Community

Edgaras
Edgaras

Posted on

3 1 1

Creating and Managing Custom systemd Services on Ubuntu

Introduction

If you've ever needed to automate an application or script to run on boot or wanted to manage a custom process, chances are you've come across systemd. As the default init system on Ubuntu, systemd controls how services are started, stopped, and managed. But did you know you can create your own custom services with systemd?

In this post, we will explore the process of creating and managing custom systemd services on Ubuntu and provide with a clear and practical approach to writing, configuring, and maintaining your own systemd services.

What is a systemd Service Unit?

A systemd service unit is a configuration file used by the systemd init system to define and manage a service on your Linux system. These services are typically long-running background processes, also known as daemons, that perform specific tasks or provide functionality. Examples include web servers, database servers, or even custom applications and scripts.

Service unit files have a .service extension and are usually located in directories like /etc/systemd/system/ for custom services or /lib/systemd/system/ for system-installed services. Each service unit file specifies how the service should behave, including how to start, stop, or restart it.

A typical service unit file consists of three main sections:

  1. [Unit]: Contains metadata and dependencies for the service, such as its description and what other services it depends on.
  2. [Service]: Defines how the service runs, including the command to execute, restart policies, and runtime options.
  3. [Install]: Specifies installation details, such as when the service should be started (e.g., at boot time).

Step 1: Creating a Basic Service File

Creating a custom service in systemd begins with writing a .service file. This file defines the behavior of your service, such as the program to run, its restart policies, and when it should start.
Start by opening a new file in the /etc/systemd/system/ directory. For this example, we’ll create a service called my-custom.service:

sudo nano /etc/systemd/system/my-custom.service
Enter fullscreen mode Exit fullscreen mode

Inside the file, define the following basic structure:

[Unit]
Description=My Custom Service
After=network.target

[Service]
ExecStart=/usr/bin/python3 /path/to/my-script.py
Restart=always
User=myuser
Group=mygroup

[Install]
WantedBy=multi-user.target
Enter fullscreen mode Exit fullscreen mode

Explanation of Each Section:

  1. [Unit]:
    • Description: A brief description of your service.
    • After: Ensures the service starts only after the network.target is reached, meaning the network is up.
  2. [Service]:
    • ExecStart: The command to start your service (in this case, a Python script).
    • Restart: Ensures the service restarts automatically if it fails.
    • User and Group: Specifies the user and group under which the service runs for security.
  3. [Install]:
    • WantedBy: Specifies that the service should be started during the multi-user.target boot phase, which is common for most services.

Once you’ve saved the file, reload the systemd daemon to recognize the new service:

sudo systemctl daemon-reload
Enter fullscreen mode Exit fullscreen mode

Step 2: Installing and Enabling the Service

Once the service file is created, the next step is to install and enable it so that it runs as expected. In systemd, "installing" essentially means notifying the system about your new service, and "enabling" ensures it starts automatically on boot.

Start the Service

To start the service immediately, use the following command:

sudo systemctl start my-custom.service
Enter fullscreen mode Exit fullscreen mode

You can verify that the service is running by checking its status:

sudo systemctl status my-custom.service
Enter fullscreen mode Exit fullscreen mode

This command will display information about the service, including whether it started successfully, its runtime status, and any logged output.

Enable the Service at Boot

To ensure the service starts automatically at boot, enable it with:

sudo systemctl enable my-custom.service
Enter fullscreen mode Exit fullscreen mode

This creates a symbolic link in the appropriate systemd directory to include your service in the boot sequence.

Reloading Changes

If you ever make changes to the .service file, you need to reload the systemd daemon to apply the updates:

sudo systemctl daemon-reload
Enter fullscreen mode Exit fullscreen mode

After reloading, restart the service to apply the changes:

sudo systemctl restart my-custom.service
Enter fullscreen mode Exit fullscreen mode

Step 3: Debugging

To ensure your custom service works as intended, follow these steps for debugging:

Start and Verify the Service

Start your service:

sudo systemctl start my-custom.service
Enter fullscreen mode Exit fullscreen mode

Check its status for runtime details:

sudo systemctl status my-custom.service
Enter fullscreen mode Exit fullscreen mode

Look for "Active: active (running)" to confirm it’s operational.

Examine Logs

Inspect logs for errors or output using:

sudo journalctl -u my-custom.service
Enter fullscreen mode Exit fullscreen mode

Advanced Features

While the basic setup of systemd services covers most use cases, advanced features provide additional flexibility and control. Some noteworthy advanced options include:

Timer Units

Instead of running services immediately, you can create timer units to schedule services at specific times or intervals. Example:

[Unit]
Description=Run custom script daily

[Timer]
OnCalendar=daily
Unit=my-custom.service

[Install]
WantedBy=timers.target
Enter fullscreen mode Exit fullscreen mode

Activate the timer with:

sudo systemctl enable my-custom.timer
sudo systemctl start my-custom.timer
Enter fullscreen mode Exit fullscreen mode

Environment Variables

You can define environment variables within the service file to customize behavior dynamically.

[Service]
Environment="VAR_NAME=value"
Enter fullscreen mode Exit fullscreen mode

Sandboxing and Security Options

Use directives like PrivateTmp=true, ProtectSystem=full, or NoNewPrivileges=true to isolate your service and limit its capabilities for enhanced security.

Dependencies

Define service dependencies using Before=, After=, and Requires= to control startup order and relationships with other services.

Common Pitfalls

Even with a straightforward setup, some common issues can arise when working with systemd services:

  • Forgetting to Reload Daemon: After creating or modifying a service file, always reload the systemd daemon with:
sudo systemctl daemon-reload
Enter fullscreen mode Exit fullscreen mode
  • Incorrect Paths or Permissions: Ensure all paths in ExecStart are correct and accessible by the user running the service. Verify permissions on scripts and executables.
  • Failure to Enable the Service: Not enabling the service results in it not starting at boot. Always use:
sudo systemctl enable my-custom.service
Enter fullscreen mode Exit fullscreen mode
  • Insufficient Logging: If a service fails silently, use journalctl -u <service-name> to diagnose issues and ensure adequate logging is set up in your scripts or applications.
  • Overlooking Dependencies: Misconfigured dependencies can cause startup delays or failures. Use After= and Requires= judiciously.

Real-World Examples

Example 1: Deploying a Web Server

Suppose you need a lightweight Python web server to start automatically on boot. Create a service file:

[Unit]
Description=Simple Python Web Server
After=network.target

[Service]
ExecStart=/usr/bin/python3 -m http.server 8080
WorkingDirectory=/home/myuser/webroot
Restart=on-failure
User=myuser
Group=mygroup

[Install]
WantedBy=multi-user.target
Enter fullscreen mode Exit fullscreen mode

Reload, start, and enable the service:

sudo systemctl daemon-reload
sudo systemctl start web-server.service
sudo systemctl enable web-server.service
Enter fullscreen mode Exit fullscreen mode

Example 2: Automating a Backup Script

For a script that backs up files nightly, create a service and timer unit:

Service file:

[Unit]
Description=Nightly Backup Service

[Service]
ExecStart=/usr/bin/bash /home/myuser/backup.sh
User=myuser
Group=mygroup
Enter fullscreen mode Exit fullscreen mode

Timer file:

[Unit]
Description=Run backup nightly

[Timer]
OnCalendar=02:00
Persistent=true

[Install]
WantedBy=timers.target
Enter fullscreen mode Exit fullscreen mode

Activate the timer:

sudo systemctl enable backup.timer
sudo systemctl start backup.timer
Enter fullscreen mode Exit fullscreen mode

Conclusion

Custom systemd services provide a powerful and flexible way to manage processes and scripts on Ubuntu. With the ability to define dependencies, schedule executions, and secure your services, systemd becomes an essential tool for developers and sysadmins alike. Avoid common pitfalls by thoroughly testing your configurations, and leverage advanced features like timers and security options to enhance functionality. Whether automating backups or deploying servers, systemd services ensure reliable and repeatable management of tasks.

Please leave your appreciation by commenting on this post!

It takes one minute and is worth it for your career.

Get started

Top comments (0)

👋 Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay