1. Overview

systemd is an init system in Linux used for managing system processes and services. We can set up systemd services by creating unit files. Sometimes, it’s necessary to specify the working directory for a systemd service when creating the unit file. This is especially useful when the service needs access to specific configuration files or auxiliary scripts during execution.

In this tutorial, we’ll explore how we can designate a working directory for systemd services.

2. Sample Task and Script

Let’s suppose we want to set up a systemd service that executes a script named getcwd.sh. The script simply prints the current working directory:

$ cat getcwd.sh
#!/usr/bin/env bash
echo "Current Working Directory: $(pwd)"

The getcwd.sh script will be used for checking the working directory of the systemd service that calls it later.

To begin with, we grant the script execute permissions using chmod:

$ chmod u+x getcwd.sh

Next, we move the script to the /usr/local/bin directory using the mv command:

$ sudo mv getcwd.sh /usr/local/bin/

In this case, we use sudo with the mv command since modifying the specified directory requires elevated privileges.

Now that the script is in place, our objective is to create a service around it using a systemd unit file and set the working directory for the service.

Let’s start by exploring how we can set up the service unit file and test its default working directory.

3. Create systemd Service for Script

At this point, we can create a systemd service unit file, named getcwd.service, which runs the getcwd.sh script when started:

$ cat getcwd.service
[Unit]
Description=Print Current Working Directory

[Service]
ExecStart=/usr/local/bin/getcwd.sh
StandardOutput=syslog
StandardError=syslog

[Install]
WantedBy=multi-user.target

The unit file consists of several components:

  1. Description directive under the [Unit] section specifies a user-defined description of the service
  2. ExecStart directive under the [Service] section specifies the path to the getcwd.sh script, which runs when the service starts
  3. StandardOutput and StandardError directives specify that the stdout and stderr messages generated by the service get redirected to the system log, which can be accessed at /var/log/syslog
  4. WantedBy directive under the [Install] section is set to multi-user.target, indicating that the service starts when the system boots and reaches the non-graphical, multi-user target

Notably, multi-user.target is equivalent to runlevel 2 or 3 in System V init.

Next, we copy the unit file to the /etc/systemd/system directory:

$ sudo cp getcwd.service /etc/systemd/system/

Finally, we can start the service using systemctl and the start subcommand:

$ systemctl start getcwd.service
==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ===
Authentication is required to start 'getcwd.service'.
Authenticating as: sysadmin,,, (sysadmin)
Password: 
==== AUTHENTICATION COMPLETE ===

To verify that the service ran successfully, we check the syslog messages:

$ sudo cat /var/log/syslog
...
Nov 18 11:03:10 debian systemd[1]: Started Print Current Working Directory.
Nov 18 11:03:10 debian getcwd.sh[2513]: Current Working Directory: /
Nov 18 11:03:10 debian systemd[1]: getcwd.service: Succeeded.

Importantly, the current working directory appears to be the root (/) directory. Therefore, this is the default directory for systemd services as well.

If we want to execute the script from a specific working directory, say /usr/local, we have two options. The first method is to modify getcwd.sh and change to the required directory at the beginning of the script:

$ cat /usr/local/bin/getcwd.sh
#!/usr/bin/env bash
cd /usr/local
echo "Current Working Directory: $(pwd)"

Alternatively, we can modify the service unit file by including a specific working directory within it.

Thus, let’s keep the getcwd.sh script in its original form and explore the second approach.

4. Set Working Directory of the systemd Service

To specify a working directory for a systemd service, we can add the WorkingDirectory directive under the [Service] section:

$ cat getcwd.service
[Unit]
Description=Print Current Working Directory

[Service]
WorkingDirectory=/usr/local
ExecStart=/usr/local/bin/getcwd.sh
StandardOutput=syslog
StandardError=syslog

[Install]
WantedBy=multi-user.target

Now, we expect the service to run the getcwd.sh script within the /usr/local directory instead of the default root directory.

To test the new unit file, we first copy it to the /etc/systemd/system directory, replacing the old version:

$ sudo cp getcwd.service /etc/systemd/system/

Then, we reload all the unit files using the systemctl deamon-reload command:

$ systemctl daemon-reload
==== AUTHENTICATING FOR org.freedesktop.systemd1.reload-daemon ===
Authentication is required to reload the systemd state.
Authenticating as: sysadmin,,, (sysadmin)
Password: 
==== AUTHENTICATION COMPLETE ===

Finally, we restart the service using the systemctl restart command:

$ systemctl restart getcwd.service
==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ===
Authentication is required to restart 'getcwd.service'.
Authenticating as: sysadmin,,, (sysadmin)
Password: 
==== AUTHENTICATION COMPLETE ===

To verify the changes made, we can check the system log at /var/log/syslog:

$ sudo cat /var/log/syslog
...
Nov 18 11:11:38 debian systemd[1]: Reloading.
Nov 18 11:11:51 debian systemd[1]: Started Print Current Working Directory.
Nov 18 11:11:51 debian getcwd.sh[2735]: Current Working Directory: /usr/local
Nov 18 11:11:51 debian systemd[1]: getcwd.service: Succeeded.

As expected, the log messages show the current working directory as /usr/local, which matches what we specified in the service unit file.

5. Conclusion

In this article, we saw how to set a working directory for a systemd service.

In particular, we can assign a given path to the WorkingDirectory directive in the [Service] section of the unit file. This causes the systemd service to run with the specified directory as its default one.

Comments are closed on this article!