Skip to content

Systemd user units

Systemd is mainly used to manage services on modern linux distributions, but it also allows non-root users to manage services running under their own account. This makes systemd a great alternative to services like supervisord as it is able to detect crashes and automatically restarts the service.

Configuring a user unit

The directory structure that holds unit files is similar to the system-wide configuration, but is located in a user's home directory.
If this directory does not exist, you can create it with the command below:

mkdir -p ~/.config/systemd/user

Navigate into this folder:

cd ~/.config/systemd/user

Here you can add a new file where the filename will also serve as the service name. For systemd to recognize it as a unit, the file must have a .service extension.

For example, if you want systemd to manage a Laravel PHP queue worker, create a file named worker.service using your preferred text editor (nano, vim, etc.), and add the following configuration:

[Unit]
Description=Laravel PHP queue worker

[Service]
ExecStart=/usr/bin/env php /path/to/my/project/artisan queue:work --sleep=3 --tries=3

[Install]
WantedBy=default.target

Notify systemd of the newly created service:

systemctl --user daemon-reload

Managing a user unit

Now you can manage this service with systemd:

  • systemctl --user start worker starts the service
  • systemctl --user stop worker stops the service
  • systemctl --user restart worker restarts the worker
  • systemctl --user status worker shows the service's status
  • systemctl --user enable worker starts the service on boot
  • systemctl --user disable worker service will not start on boot
  • systemctl --user daemon-reload notify systemd to reload changes
Editing the .service file

When making changes to the .service file, don't forget to run systemctl --user daemon-reload to make systemd aware of your changes before restarting the service.

Starting user services at boot

By default, systemd starts enabled user units when the user logs in, and stops them once the user has logged out. This is great for desktop pcs where a user wants to run things while he's using the computer. On servers, however, we may want to run those units all the time. To ensure that services don’t stop when a user logs out, and automatically starts again on boot, lingering must be enabled for that user.
We enable lingering by default for all SOCK users, so the only thing left to do is enabling your service:

systemctl --user enable worker

Viewing logs

Everything our PHP script writes to stdout and stderr will be recorded by journald.
We can view the logs for this specific service:

journalctl -u worker

Automatically restarting on failure

Let's be honest: things go wrong. When our worker crashes we want to make sure it's started again.
Fortunately, we can configure systemd to restart on failure:

Add the following to the [Service] section of the unit file:

RestartSec=10s
Restart=on-failure

This makes systemd restart the service 10 seconds after it has stopped with a non-zero exit code. If the process exited cleanly, systemd considers the work as done and won't restart the service until you manually start it later.