It’s been a long while that Unix used init.d to manage services.
But it comes with two shortages: the one thing is that what it only does is run a simple script, no more, no less. So, the script itself needs to handle all the other stuff, like executing some command after another service is started, etc. The other thing is, init.d execute all the scripts sequentially, it makes the machine start slow.
Therefore, Lennart Poettering wrote Systemd to be a replacement. To be clear, not everyone thinks init.d didn’t do its job well, because it’s separate from the operating system while Systemd doesn’t, so it’s violating “Unix philosophy“.
As Systemd is a big topic to focus on, this article will only cover the most common usages of Systemd. For more information, refer to wikis like ArchWiki, or if you prefer an old-class, textbook like document, try this.
systemctl start nginx # Start a Servce systemctl stop nginx # Stop a Service systemctl restart nginx # Restart a Service
Unit is a file format how Systemd recognize a “startup task” (service in fact).
Unit files can be stored in multiple places, and you can check it on your own system by running this command.
systemctl show --property=UnitPath
In most cases. it will be stored in /etc/systemd/system/ for system provided units, and /usr/lib/systemd/system/ for units provided by installed packages. But if you want a “task” to start automatically at boot, it must be linked to
Enable & disable
As we mentioned before, Systemd is built to simplify the boot process. So, the symbolic link to
/etc/systemd/system/ would be created by enable & disable command. The two following are doing the identical thing.
systemctl enable unitname.service
ln -s '/usr/lib/systemd/system/unitname.service''/etc/systemd/system/multi-user.target.wants/unitname.service'
Did you see the “ulti-user.target.wants” in the last command? That’s the second to last thing you must know about Systemd, target.
A system will have significant amounts of units to be started up in a single boot. So, grouping some units together and starting them at once will be better than specifying which unit should be started separately.
So, if you want your application to run automatically when the system boots into command line (which is destined to happen Lol), just add your unit into “group” multi-user.target. If your application needs graphical interface to function, then add your unit into “group” graphical.target.
To demonstrate which target is started by default, run
The unit file is made up with serval blocks. All the information like the name of the unit, what to do when start/restart/stop the unit, and so on.
The starting block usually is [Unit]. It defines what this unit is and the relationship with other units. The most used fields are listed below, while full references are available here.
|Description||Do what you think it Dose.|
|Documentation||A space-separated list of URIs referencing documentation for this unit or its configuration.|
|Wants||Configures (weak) requirement dependencies on other units. If the listed units fail to start or cannot be added to the transaction, this has no impact on the validity of the transaction, and this unit will still be started.|
|Requires||Like Wants but declares a stronger requirement dependency.|
|BindsTo||Configures requirement dependencies, similar in style to |
|Before/After||Those two settings configure ordering dependencies between units. If unit |
|Conflicts||Configures negative requirement dependencies. If a unit has a |
The following block could be [Service]. It defends the most behavior of our unit. The most used fields are listed below, while full references are available here.
|ExecStart||Commands with their arguments that are executed when this service is started.|
|ExecReload||Commands to execute to trigger a configuration reload in the service.|
|ExecStop||Commands to execute to stop the service started via |
|Restart||Configures whether the service shall be restarted when the service process exits, is killed, or a timeout is reached.|
Takes one of
In addition, I would recommend using “
on-failure” for field Restart for most common situations, because in most cases, errors that occur with programs that are set to start automatically are transient. Restarting them helps.
Also in most cases, ExecStart is the only field you need to care about, since stop and restart commands will handle all the processes that started by ExecStart.
This is the last block in a unit file. It is used to define which target this unit is to start with.
|WantedBy||A symbolic link is created in the |
WantedBy usually takes one of graphical.target, multi-user.target. Note that graphical.target depends on multi-user.target.
This example is going to show a simple service that executes a executable file when machine starts.
First step of course, creating a unit file. Since it is just a plain text file, nano will be decent.
cd /usr/lib/systemd/system/ sudo nano unitname.service
Then write the unit file.
[Unit] Description=Some HTTP server After=remote-fs.target sqldb.service memcached.service Requires=sqldb.service memcached.service [Service] ExecStart=/usr/sbin/some-fancy-httpd-server [Install] WantedBy=multi-user.target
Save the file.
Then reload the Systemd daemon list.
Last, enable the unit.
systemctl enable unitname