5

This questions stems from @FrustratedWithFormsDesigner comment.

How do I make export environment variables set within an init.d script available to downstream processes started within that same init.d script?

In more detail, I am on an Amazon EC2 instance and using an init.d script to control my node.js server that is in turn controlled by nodemon which monitors for file changes and restarts node as needed. So in short, my init.d script starts nodemon which then starts node. Environment variables set with export within the init.d script seem to be available to nodemon, but unavailable to node. How do I make these environment variables available to node as well?

Currently, only init.d is available in my Amazon EC2 instance so is this even possible with init.d scripts, and if not, is this possible with upstart or preferably systemd?

  • 1
    I'm not familiar with nodemon, but it sounds to me like nodemon is deciding which variables to pass on to its children processes; if you've exported them from the init script, you now need to focus on nodemon. – Jeff Schaller Jun 5 '16 at 12:20
  • In my particular situation, you are right; nodemon should be handling the environment variables and not the init.d script itself. For this reason and others, I have switched to pm2 which is far better than nodemon at handling environment variables. – Marc A Jun 5 '16 at 16:26
  • Still though, I think this is a valuable question that if answered, could help a few out there that were in a similar position as myself. If there is really no solution specific to the question asked, please post your comment @JeffSchaller as an answer, so that I may mark it as correct. – Marc A Jun 5 '16 at 16:33
  • Glad you found another way that works. No idea how to fix the issue, but there is an alternative when bash or another shell won't pass variables the way you need it to. You can write your data to files either as pure data you can read or as bash/shell code you source (if it doesn't open security holes) in subsequent scripts. The trick is using process ID or something similar in the file names so that each script gets the right file when multiple instances are running. If you put them all in a directory under /tmp, you can delete the whole thing when done instead of tracking each one. – Joe Jun 10 '16 at 20:56
4

I recommend switching to a systemd based Linux distro, like Fedora or Ubuntu 16.04. systemd can easily pass environment variables to your process AND it can handle automatically restarting your process it fails as well as starting it at boot. Logging is also nicely handled by systemd`s journald. There's also not the overhead of installing or running anything else, since systemd is part of of the OS distribution.

Here's an example of setting two environment environment variable with systemd in a unit file:

Environment="ONE=one" 'TWO=two two'

Full docs are here.

Your problem was partly one of complexity, as both the init system and the process manager handled passing environment variables. With systemd as both the init system and the process manager, a layer of complexity is removed.

  • I started to edit your answer, but perhaps it is better if someone more experienced like yourself add a tiny how-to on systemd environment directives and conf drop-ins? If you do, I will mark this answer as correct. – Marc A Jun 24 '16 at 0:15
  • I added example syntax for setting systemd environment variables. I'm not sure about the "conf drop-ins" you are referring to. That's not a term I used. What's a "conf drop-in" ? – Mark Stosberg Jun 24 '16 at 13:33
  • Sorry, conf drop-ins may be specific to CoreOS only. What I was trying to refer to was the EnvironmentFIle directive. Please see my answer below. – Marc A Jun 28 '16 at 13:47
4

In addition to using Environment directive in the systemd service itself as suggested in this answer, another option is the EnvironmentFile directive.

Please note that I am no expert in this area (obviously, I am the author of this question); I am only summarizing to the best of my ability the Fedora Wiki. Feel free to edit/correct me.

EnvironmentFile directive

Create a file containing new-line-separated variable assignments:

# myservice.env
ENV1=value1
ENV2=value2

Then, in your service unit file, use the EnvironmentFile directive:

[Service]
...
EnvironmentFile=-/path/to/myservice.env
...

Within your unit file, use ${ENV1} and $ENV1 to refer to the variables set within myservice.env.

The "-" on the EnvironmentFile= line ensures that no error messages is generated if the environment file does not exist.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.