1. Overview
The systemd utility manages services in Linux systems. That is, it configures and runs other programs in the background.
In this tutorial, we’ll learn how to set environment variables for such tasks.
2. Preparing Service
Let’s write a simple bash script test_env_service to act as a service. To be precise, its only goal is to dump the script’s environment with env:
#!/bin/bash
while true
do
env
sleep 10
done
Now, we’re going to copy it to /usr/local/bin and make it executable. Then, let’s prepare the unit file test_env_service.service in /etc/systemd/system:
[Unit]
Description=Script Daemon For Test Environmnent Variables
[Service]
Type=simple
User=joe
ExecStart=/usr/local/bin/test_env_service
Restart=on-failure
[Install]
WantedBy=default.target
Next, let’s install, enable and start it with:
$ sudo systemctl daemon-reload
$ sudo systemctl enable test_env_service.service
$ sudo systemctl start test_env_service.service
Finally, let’s state that we work on Fedora 35 with systemd version systemd 249 (v249.11-2.fc35).
3. Setting Variables With Environment
In the unit file, let’s define the FOO variable by the Environment tag from the Service section:
[Service]
# ...
Environment="FOO=foo"
Next, we need to reload services and restart test_env_service. Then, let’s check its logs with journalctl:
$ journalctl -xeu test_env_service
#...
Jul 16 04:24:42 fedora35 test_env_service[5657]: FOO=foo
#...
Finally, let’s notice that we can provide a space delimited list of variables in one Environment entry. Moreover, multiple entries are allowed as well.
4. Overriding Service Configuration
The configuration in the unit file in /etc/systemd/system may be a common one from the service distribution. So to avoid making changes to such a file, let’s override the configuration in a way supported by systemd. We can do that with sudo systemctl edit test_env_service, which creates a folder /etc/systemd/system/test_env_service.service.d with file override.conf.
The structure of the file corresponds to the structure of the unit file. Furthermore, entries of this file override their counterparts from /etc/systemd/system. Now, let’s change our variable FOO with the entry in override.conf:
[Service]
Environment="Foo=bar"
Next, after reloading and restarting, let’s look into the log:
Jul 16 04:37:42 fedora35 test_env_service[6627]: FOO=bar
5. Reading Variables From a File With EnvironmentFile
Now, let’s use the EnvironmentFile entry to point to the file with environment variables:
[Service]
# ...
EnvironmentFile=/etc/test_env_service/var_file
Next, let’s take a look at the file’s content and notice its simple VarName=VarValue format:
FILE_VAR1="Variable 1 from environment file"
FILE_VAR2="Variable 2 from environment file"
Then, we should place var_file in the newly created /etc/test_env_service folder to make it accessible by systemd. And finally, let’s reload daemons, restart the service and examine the log:
Jul 16 05:00:11 fedora35 test_env_service[8069]: FILE_VAR1=Variable 1 from environment file
Jul 16 05:00:11 fedora35 test_env_service[8069]: FILE_VAR2=Variable 2 from environment file
6. Why Separate File
systemd doesn’t natively support using a separate file. Moreover, this way is competitive with configuration overriding. However, we should use it if the variables contain some secret data. First, the configuration from both the unit file and override.conf is available to any user:
$ systemctl show test_env_service.service
# ... Environment=FOO=bar
EnvironmentFiles=/etc/test_env_service/var_file (ignore_errors=no)
# ...
So with the show command to systemctl, we see the FOO definition, but not the content of the var_file. Next, if we’re going to share our service, we can accidentally publish all sensitive data in the systemd files.
7. Accessing Variables Within the Unit File
Let’s notice that the variables defined in the unit file aren’t available only in the daemon’s environment. Moreover, in the unit file, we can refer to them as ${VarName} or $VarName. Now, let’s modify our script to print its argument in a comma-separated list with the help of the shell build-in printf:
#!/bin/bash
while true
do
printf -v list '%s,' "$@"
echo "${list%,}"
sleep 10
done
Next, let’s pass variables to the script in the unit file:
[Service]
# ...
Environment="FOO=foo"
EnvironmentFile=/etc/test_env_service/var_file
ExecStart=/usr/local/bin/test_env_service $FOO ${FILE_VAR1} ${FILE_VAR2}
And as usual, let’s check the logs – we should recall that FOO is overridden:
Jul 16 06:38:23 fedora35 test_env_service[12852]: bar,Variable 1 from environment file, Variable 2 from environment file
8. Conclusion
In this tutorial, we examined ways to set environment variables for daemons managed by systemd. Thus, we defined the variables in the unit file and imported them from a separate file. In addition, we learned how to override service configuration. Finally, we referred to variables inside the unit file.