20

I've built an application and a systemd unit for it. The systemd unit works fine, but as the dev and prod environments have diverged I've started moving config out to environment variables and I can't seem to get them to work in systemd.

I've tried system-wide environment variables, and they're visible to the OS, but not the program, so i started looking at building them into systemd units.

First I tried using EnvironmentFile

I created an environment file that simply had

LCSQLH=localhost
LCSQLU=application

in it as /etc/lc.sh and

[Unit]
Description=Service for this app

[Service]
EnvironmentFile=/etc/lc.sh
ExecStart=/usr/bin/env python /opt/app/__init__.py

did a systemctl --system daemon-reload but no, my app errored:

Jan 27 14:24:59 machine.host env[630]: KeyError: 'LCSQLU'

I saw some had:

EnvironmentFile=-/etc/lc.sh

I tried that.... nope...

So I tried putting them in individually

[Service]
Environment="LCSQLH=localhost"
Environment="LCSQLU=application"
ExecStart=/usr/bin/env python /opt/app/__init__.py

Yet again, no...

So I heard about the idea of /etc/systemd/service_name.service.d so I put a service.conf in there with the environments in (same format as above) but no...

My application has no access to these environment variables.

If I export them (either manually in my shell or using /etc/profile.d/) and run my app directly it works, so it is that these aren't being set rather than an app issue.

This is Centos 7.3 and I've chosen environment variables rather than a hardcoded config because it may run on either linux or windows, so don't want to bury a config file in /etc/

3
  • 1
    Seems to be working here, are you running systemctl daemon-reload and stop start your application each time to test your modifications?
    – rogerdpack
    Commented May 30, 2019 at 17:00
  • 1
    Having the same problem on CentOS8, and this issue has (3.5 years after asking) 31k views. Did you ever solve this problem? Commented Oct 21, 2020 at 18:58
  • 1
    How depressing to run into this problem again, and then find my own comment. Sorry old me, it still hasn't been fixed. Commented May 4, 2022 at 11:24

2 Answers 2

10

I ran into the same trouble on RHEL 7.3 and found this:

You may then refer to variables set in the /etc/sysconfig/httpd file with ${FOOBAR} and $FOOBAR, in the ExecStart lines (and related lines).

This makes me think that the purpose for Environment and EnvironmentFile is not at all what you and I expected (setting environment variables for the process started by the systemd unit), but only applies for the immediate expansion of the ExecStart line.

Perhaps I'm completely off-base and this is a bug in systemd (I hope so). But I stopped going down the path you are trying and did it another way: In my case I needed to set LD_LIBRARY_PATH, so I did that via creating /etc/ld.so.conf.d/new_file.conf and then running ldconfig. I also attempted to use system-wide variables in /etc/profile.d/new_file.sh, but apparently setting just LD_LIBRARY_PATH was enough for this service (mariadb) and so I don't actually know if the variables I was setting in /etc/profile.d/new_file.sh were functioning.

38

Environment and EnvironmentFile set the variables, usable by the unit, but like the sh command, does not export it to child processes. For that, you also need to list it in PassEnvironment, just as you would with the export shell command. See the systemd documentation on EnvironmentFile and PassEnvironment

Also, note that the contents of an EnvironmentFile is not a shell script, but key-value pairs that look rather too much like sh, so naming it with a .sh extension is misleading.

2
  • 4
    Also worth noting that a careful reading of those docs also reveals why these variables seem to pass through for some configurations "system services by default do not automatically inherit any environment variables [...] However, in case of the user service manager all environment variables are passed to the executed processes"
    – 7yl4r
    Commented Mar 5, 2018 at 19:35
  • 2
    I just tested this out using ExecStartPre=/bin/bash -l -c 'env >/tmp/ingest.err' and env. var's set using Environment= and EnvironmentFile= and systemctl set-environment... do show up in the env of the unit...even if it's a system unit. The only explanation I can must is that PassEnvironment means to pass variables in the env. of the systemd process itself "through" (see comment superuser.com/a/728962/39364). FWIW...
    – rogerdpack
    Commented May 30, 2019 at 16:56

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .