Walkthrough: How to start a long-running command on boot with systemd
Creating the Systemd Unit
Systemd is a process manager that can start, stop, and manage processes ("Units") on boot or shutdown of your machine![1]
In this walkthrough, we'll be starting a long-running Node.js web server that lives in /var/www/.
To create a new Unit, we need to create a file in /etc/systemd/system/ (the default location on most Linux distributions).
This file should have the .service extension.
Let's create /etc/systemd/system/webserver.service:
[Unit]
# Since we're going to bind to a port on localhost, we need to wait for the
# network to be available:
After=network.target
Description=My fancy web server
[Service]
# Set the working directory to where your application lives
WorkingDirectory=/var/www
# Set any environment variables your application needs
Environment=NODE_ENV=production
Environment=PORT=3000
# Start your webserver (absolute path required - find yours with `which node`)
ExecStart=/usr/bin/node server.js
# Restart the service if it crashes
Restart=always
# Wait 3 seconds before restarting
RestartSec=3
[Install]
# Start this service when the system boots to multi-user mode
WantedBy=multi-user.target
After you've created the file, update it to have the correct permissions (664):
chmod 664 /etc/systemd/system/webserver.service
Don't be intimidated by the file above! A lot of it is boilerplate. Read the comments placed in the above file to understand what each section is for!
Note: Comments in systemd unit files must be on their own line—inline comments after values are not supported.[2] The
ExecStartdirective requires an absolute path to the executable.[3]
You can learn more about the Unit or Service sections in the systemd documentation.
The Install section is used to configure when the service will start. Most commonly, you'll want multi-user.target.[4]
The WantedBy value directly corresponds to different Linux runlevels:
| runlevel | WantedBy value | Description |
|---|---|---|
| 0 | poweroff.target |
Run before the computer shuts down |
| 1 | rescue.target |
Run when the system is in single-user mode |
| 2-4 | multi-user.target |
Non-graphical multi-user system (networking available) |
| 5 | graphical.target |
Run when the display manager has started |
| 6 | reboot.target |
Run before the computer reboots |
Enabling the Systemd Unit
Now that the unit has been created, we need to reload the Systemd process. This will allow Systemd to recognize the new file.
Run the following command:
systemctl daemon-reload
Tip: You need to execute the above command to reload Systemd every time you edit your
.servicefile(s).
Next, you'll need to enable the service. Running this command will create a symlink into your WantedBy target.
systemctl enable webserver
Finally, since your system is already booted, run the following command to start the service:
systemctl start webserver
Cheatsheet
Enabling (creating) or Disabling (deleting) your service
systemctl enable webserver # enable service to start on boot
systemctl disable webserver # disable service from starting on boot
Starting, Restarting, or Stopping your service
systemctl start webserver
systemctl restart webserver
systemctl stop webserver
Checking the status of your service
systemctl status webserver
[1] freedesktop.org. "systemd.unit — Unit configuration". systemd documentation.
[2] freedesktop.org. "systemd.syntax — General syntax of systemd configuration files". "Lines beginning with '#' or ';' are ignored."
[3] freedesktop.org. "systemd.service — Service unit configuration". "The first argument must be either an absolute path or a simple file name without any slashes."
[4] Red Hat. "Working with systemd unit files". RHEL 9 Documentation.