I have an Arch Linux system with systemd and I've created my own service. The configuration service at /etc/systemd/system/myservice.service
looks like this:
[Unit]
Description=My Daemon
[Service]
ExecStart=/bin/myforegroundcmd
[Install]
WantedBy=multi-user.target
Now I want to have an environment variable set for the /bin/myforegroundcmd
. How do I do that?
Times change and so do best practices.
The current best way to do this is to run
systemctl edit myservice
, which will create an override file for you or let you edit an existing one.In normal installations this will create a directory
/etc/systemd/system/myservice.service.d
, and inside that directory create a file whose name ends in.conf
(typically,override.conf
), and in this file you can add to or override any part of the unit shipped by the distribution.For instance, in a file
/etc/systemd/system/myservice.service.d/myenv.conf
:Also note that if the directory exists and is empty, your service will be disabled! If you don't intend to put something in the directory, ensure that it does not exist.
For reference, the old way was:
The recommended way to do this is to create a file
/etc/sysconfig/myservice
which contains your variables, and then load them withEnvironmentFile
.For complete details, see Fedora's documentation on how to write a systemd script.
The answer depends on whether the variable is supposed to be constant (that is, not supposed to be modified by user getting the unit) or variable (supposed to be set by the user).
Since it's your local unit, the boundary is quite blurry and either way would work. However, if you started to distribute it and it would end up in
/usr/lib/systemd/system
, this would become important.Constant value
If the value doesn't need to change per instance, the preferred way would be to place it as
Environment=
, directly in the unit file:The advantage of that is that the variable is kept in a single file with the unit. Therefore, the unit file is easier to move between systems.
Variable value
However, the above solution doesn't work well when sysadmin is supposed to change the value of the environment variable locally. More specifically, the new value would need to be set every time the unit file is updated.
For this case, an extra file is to be used. How — usually depends on the distribution policy.
One particularly interesting solution is to use
/etc/systemd/system/myservice.service.d
directory. Unlike other solutions, this directory is supported by systemd itself and therefore comes with no distribution-specific paths.In this case, you place a file like
/etc/systemd/system/myservice.service.d/local.conf
that adds the missing parts of unit file:Afterwards, systemd merges the two files when starting the service (remember to
systemctl daemon-reload
after changing either of them). And since this path is used directly by systemd, you don't useEnvironmentFile=
for this.If the value is supposed to be changed only on some of the affected systems, you may combine both solutions, providing a default directly in the unit and a local override in the other file.
http://0pointer.de/public/systemd-man/systemd.exec.html#Environment= - you have two options (one already pointed by Michael):
and
The answers by Michael and Michał are helpful and answer the original question of how to set an environment variable for a systemd service. However, one common use for environment variables is to configure sensitive data like passwords in a place that won't accidentally get committed to source control with your application's code.
If that's why you want to pass an environment variable to your service, do not use
Environment=
in the unit configuration file. UseEnvironmentFile=
and point it to another configuration file that is only readable by the service account (and users with root access).The details of the unit configuration file are visible to any user with this command:
I put a configuration file at
/etc/my_service/my_service.conf
and put my secrets in there:Then in my service unit file, I used
EnvironmentFile=
:I checked that
ps auxe
can't see those environment variables, and other users don't have access to/proc/*/environ
. Check on your own system, of course.Michael gave one clean solution but I wanted to get updated env variable from script. Unfortunately executing bash commands is not possible in systemd unit file. Fortunately you can trigger bash inside ExecStart:
http://www.dsm.fordham.edu/cgi-bin/man-cgi.pl?topic=systemd.service&sect=5
Example in our case is then:
Don't use Environment= or EnvironmentFile= for credentials / secrets.
Per https://www.freedesktop.org/software/systemd/man/systemd.exec.html#Environment
You should use
LoadCredential=, LoadCredentialEncrypted= or SetCredentialEncrypted=