Services, services, services. A service is a huge part of computing. You're reading this article on a service. Your computer is running services. The internet is filled with them.
On Linux, the standard way of running and managing services is through the systemd utility and the command
systemctl. Its usage is fairly simple: you just need to know the name of the service you want to manage, then you can use this command to start or stop the service, check its status, or do other functions:
# systemctl start httpd # systemctl stop httpd # systemctl status httpd
A service is defined in a file called a unit file. They are generally located in the directory
/usr/lib/systemd/system. Here's a sample list:
# ls /usr/lib/systemd/system auditd.service multi-user.target sys-kernel-debug.mount autovt@.service multi-user.target.wants sys-kernel-tracing.mount basic.target NetworkManager-dispatcher.service syslog.socket basic.target.wants NetworkManager.service syslog.target.wants blk-availability.service NetworkManager-wait-online.service
Sometimes you need to run more than one instance of a service on a single host. For example, if you are maintaining websites for several clients, security regulations demand that each client has its own individual instance. This means you need to run a new Apache HTTP service for each, but having a lot of services can be tough to manage. If you have 10 different customers, you would have to create 10 separate unit files to manage them. Fortunately, there is a better way to handle multiple instances of a service.
The @ symbol
Notice that some of the unit files have an @ symbol in their name. This symbol has an interesting significance. As a matter of fact, after installing Apache HTTP Server, you may notice several service unit files, including one that has the @ symbol in its name—
I will show you how this can make a system administrator's life a little easier, using the Apache HTTP Server for this example:
# dnf -y install httpd # cd /usr/lib/systemd/system # ls -d http* httpd.service httpd@.service httpd.service.d httpd.socket httpd.socket.d
The @ symbol indicates that a substitution will be made. Systemd will take whatever you type after it and replace the variable
%i inside the service unit file. The variable can be seen in this excerpt of the
[Unit] Description=The Apache HTTP Server After=network.target remote-fs.target nss-lookup.target Documentation=man:httpd@.service(8) [Service] Type=notify Environment=LANG=C Environment=HTTPD_INSTANCE=%i ExecStartPre=/bin/mkdir -m 710 -p /run/httpd/instance-%i ExecStartPre=/bin/chown root.apache /run/httpd/instance-%i ExecStartPre=/bin/mkdir -m 700 -p /var/lib/httpd/instance-%i ExecStartPre=/bin/chown apache.apache /var/lib/httpd/instance-%i ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND -f conf/%i.conf ExecReload=/usr/sbin/httpd $OPTIONS -k graceful -f conf/%i.conf
Note that the default httpd unit file,
httpd.service, does not have the @ symbol in its name and looks different. It is used for a single basic default instance of the Apache HTTP server.
Run multiple instances
To run multiple instances using this special unit file, each one needs a unique name. Suppose you have two clients, The Little Bank and The Big Bank. Name the instances littlebank and bigbank. To manage one, just append its name after the @ symbol. Start each instance with the appropriate command:
systemctl start httpd@littlebank
systemctl start httpd@bigbank
Keep in mind that most services need certain configurations to avoid conflicts between different instances. I will not cover all of them here, but Apache needs several things, including unique listen port numbers, PID files, and document roots.
I'll demonstrate by trying to start the littlebank instance. I expect it to fail, but it will provide a useful status message:
# systemctl start httpd@littlebank # systemctl status httpd@littlebank ● firstname.lastname@example.org - The Apache HTTP Server Loaded: loaded (/usr/lib/systemd/system/httpd@.service; disabled; vendor preset: disabled) Active: failed (Result: exit-code) since Tue 2020-11-10 11:41:20 EST; 1min 58s ago Docs: man:httpd@.service(8) Process: 2205 ExecStartPre=/bin/mkdir -m 710 -p /run/httpd/instance-littlebank (code=exited, status=0/SUCCESS) Process: 2207 ExecStartPre=/bin/chown root.apache /run/httpd/instance-littlebank (code=exited, status=0/SUCCESS) Process: 2208 ExecStartPre=/bin/mkdir -m 700 -p /var/lib/httpd/instance-littlebank (code=exited, status=0/SUCCESS) Process: 2209 ExecStartPre=/bin/chown apache.apache /var/lib/httpd/instance-littlebank (code=exited, status=0/SUCCESS) Process: 2210 ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND -f conf/littlebank.conf (code=exited, status=1/FAILURE) Main PID: 2210 (code=exited, status=1/FAILURE) CPU: 26ms Nov 10 11:41:20 localhost.localdomain systemd: Starting The Apache HTTP Server... Nov 10 11:41:20 localhost.localdomain httpd: httpd: Could not open configuration file /etc/httpd/conf/littlebank.conf> Nov 10 11:41:20 localhost.localdomain systemd: email@example.com: Main process exited, code=exited, status=1/FAIL> Nov 10 11:41:20 localhost.localdomain systemd: firstname.lastname@example.org: Failed with result 'exit-code'. Nov 10 11:41:20 localhost.localdomain systemd: Failed to start The Apache HTTP Server.
You can see that systemd correctly substitutes the instance name in place of the
%i variable in the unit file. However, Apache fails to start because it could not open a configuration file. So, now I'll set up the instances to include creating the necessary configuration files (
# ls /etc/httpd/conf bigbank.conf httpd.conf littlebank.conf
Now you can manage each instance with
status commands to each. I've shortened the output to the most relevant details:
# systemctl start httpd@bigbank # systemctl start httpd@littlebank # systemctl status httpd@bigbank ● email@example.com - The Apache HTTP Server Loaded: loaded (/usr/lib/systemd/system/httpd@.service; disabled; vendor preset: disabled) Active: active (running) since Tue 2020-11-10 12:26:06 EST; 56min ago # systemctl status httpd@littlebank ● firstname.lastname@example.org - The Apache HTTP Server Loaded: loaded (/usr/lib/systemd/system/httpd@.service; disabled; vendor preset: disabled) Active: active (running) since Tue 2020-11-10 12:25:58 EST; 55min ago
Here is the process view of these instances. There is more than one because Apache is forking server processes, which it normally does:
# pgrep -a httpd 2834 /usr/sbin/httpd -DFOREGROUND -f conf/littlebank.conf 2835 /usr/sbin/httpd -DFOREGROUND -f conf/littlebank.conf 2836 /usr/sbin/httpd -DFOREGROUND -f conf/littlebank.conf 3061 /usr/sbin/httpd -DFOREGROUND -f conf/bigbank.conf 3062 /usr/sbin/httpd -DFOREGROUND -f conf/bigbank.conf 3064 /usr/sbin/httpd -DFOREGROUND -f conf/bigbank.conf
Put it to use
This small systemd feature is very useful when you need many instances of a service. I hope you will be able to put it to good use in your work.