Creating a Linux service with systemd

Crafting your own services — Photo by Jeff Sheldon on Unsplash

While writing web applications, I often need to offload compute-heavy tasks to an asynchronous worker script, schedule tasks for later, or even write a daemon that listens to a socket to communicate with clients directly.

While there might sometimes be better tools for the job — always consider using existing software first, such as a task queue server —writing your own service can give you a level of flexibility you’ll never get when bound by the constraints of third-party software.

The cool thing is that it’s fairly easy to create a Linux service: use your favourite programming language to write a long-running program, and turn it into a service using systemd.

The program

Let’s create a small server using PHP. I can see your eyebrows rising, but it works surprisingly well. We’ll listen to UDP port 10000, and return any message received with a ROT13 transformation:

Let’s start it:

$ php server.php

And test it in another terminal:

$ nc -u 10000
Hello, world!
Uryyb, jbeyq!

Cool, it works. Now we want this script to run at all times, be restarted in case of a failure (unexpected exit), and even survive server restarts. That’s where systemd comes into play.

Turning it into a service

Let’s create a file called /etc/systemd/system/rot13.service:

Description=ROT13 demo service
ExecStart=/usr/bin/env php /path/to/server.php


You’ll need to:

  • set your actual username after User=
  • set the proper path to your script in ExecStart=

That’s it. We can now start the service:

$ systemctl start rot13

And automatically get it to start on boot:

$ systemctl enable rot13

Going further

Now that your service (hopefully) works, it may be important to dive a bit deeper into the configuration options, and ensure that it will always work as you expect it to.

Starting in the right order

You may have wondered what the After= directive did. It simply means that your service must be started after the network is ready. If your program expects the MySQL server to be up and running, you should add:


Restarting on exit

By default, systemd does not restart your service if the program exits for whatever reason. This is usually not what you want for a service that must be always available, so we’re instructing it to always restart on exit:


You could also use on-failure to only restart if the exit status is not 0.

By default, systemd attempts a restart after 100ms. You can specify the number of seconds to wait before attempting a restart, using:


Avoiding the trap: the start limit

I personally fell into this one more than once. By default, when you configure Restart=always as we did, systemd gives up restarting your service if it fails to start more than 5 times within a 10 seconds interval. Forever.

There are two [Unit] configuration options responsible for this:


The RestartSec directive also has an impact on the outcome: if you set it to restart after 3 seconds, then you can never reach 5 failed retries within 10 seconds.

The simple fix that always works is to set StartLimitIntervalSec=0. This way, systemd will attempt to restart your service forever.

It’s a good idea to set RestartSec to at least 1 second though, to avoid putting too much stress on your server when things start going wrong.

As an alternative, you can leave the default settings, and ask systemd to restart your server if the start limit is reached, using StartLimitAction=reboot.

Is that really it?

That’s all it takes to create a Linux service with systemd: writing a small configuration file that references your long-running program.

Systemd has been the default init system in RHEL/CentOS, Fedora, Ubuntu, Debian and others for several years now, so chances are that your server is ready to host your homebrew services!




Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Getting started with Twint

How many eggs should a woodchuck chuck?

IEEE Discover Badge Challenge 2020

Working with TDD

Walk into the Pi World

Understanding Trie Databases in Ethereum

CodeLab — Connect Actions on Google with BigQuery

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Benjamin Morel

Benjamin Morel

More from Medium


How to ssh into GCP using Windows Terminal

Passwordless Authentication in linux