I have the following unit file:

Description=Panel for Systemd Services

ExecStartPre=/bin/mkdir /run/pysd
ExecStartPre=/bin/chown -R pysd:pysd /run/pysd
ExecStart=/usr/local/bin/gunicorn app:app -b --pid /run/pysd/pysd.pid --workers=2
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
ExecStopPost=/bin/rm -rf /run/pysd


I would like to create an environment variable with ExecStartPre and then incorporating this variable to ExecStart.

To be more specific, I want to create an environment variable GUNICORN_SERVER, before running the ExecStart, and then using this environment variable for the option -b at ExecStart.

I tried something like ExecStartPre=/bin/bash -c 'export GUNICORN_SERVER=', but no environment variable was created.

How do I achieve this scenario?

  • 1
    Why not just Environment=GUNICORN_SERVER=
    – muru
    Apr 11 '19 at 4:22
  • I tried this, and it seemed to work fine, but I'm not sure of the results, when using os.environ.get('GUNICORN_SERVER') on my Python application. I have to review here.. Tks anyway, muru.
    – ivanleoncz
    Apr 11 '19 at 4:27
  • 3
    You really should read the Gunicorn doco. It documents a systemd service unit, the RuntimeDirectory part of which you have laboriously reinvented. It also documents a systemd socket unit.
    – JdeBP
    Apr 11 '19 at 5:46

You cannot use ExecStartPre to directly set the environment for other ExecStartPre or ExecStart commands - those are all separate processes. (Indirectly, by saving to a file and reading it or something, sure.)

Systemd has two ways to set the environment: Environment= and EnvironmentFile=. There are examples of both in man 5 systemd.exec. These affect all processes started by the service, including those for ExecStartPre. If these variables don't have to dynamically set, those are a good option:


However, if you need to dynamically set the variables, the manpage says this about EnvironmentFile:

The files listed with this directive will be read shortly before the process is
executed (more specifically, after all processes from a previous unit state
terminated. This means you can generate these files in one unit state, and read it
with this option in the next).

So, one option would be to write it to a file in ExecStartPre, and have systemd read that file as part of EnvironmentFile:

ExecStartPre=/bin/bash -c 'echo foo=bar > /some/env/file'
ExecStart=/some/command  # sees bar as value of $foo

Another option would be to use a shell in ExecStart:

ExecStart=/bin/sh -c 'export GUNICORN_SERVER=; exec /usr/local/bin/gunicorn ...'
  • 3
    The systemd people do not like this. unix.stackexchange.com/a/419061/5132
    – JdeBP
    Apr 11 '19 at 5:35
  • @JdeBP interesting, and makes sense. I always found it weird to have an EnvironmentFile jutting into a cascading series of service files.
    – muru
    Apr 11 '19 at 5:48
  • 2
    Also note that the systemd people would say to use a socket unit to describe the listening socket, and the Gunicorn doco actually has one.
    – JdeBP
    Apr 11 '19 at 5:49
  • 3
    Unfortunately writing it to a file in ExecStartPre doesn't seem to work because it actually reads that file before running the ExecStartPre's, one workaround here: stackoverflow.com/a/42841480/32453
    – rogerdpack
    May 18 '19 at 1:31
  • Nice suggestion using /bin/sh -c '...'
    – Duke
    Apr 9 '21 at 6:55

Indeed, the best approach, is to use the --env from Gunicorn, which creates an environment variable on the OS, which you can read and incorporate the data to your Python application:

On your unit file:

ExecStart=/usr/local/bin/gunicorn app:app -b --env GUNICORN_SERVER="" --pid /run/pysd/pysd.pid --workers=2

On your application (Flask, for example):

import os
from flask import Flask

app = Flask(__name__)

gs = os.getenv('GUNICORN_SERVER')
if gs:
    app.config["SERVER_NAME"] = gs                                              
    app.config["SERVER_NAME"] = ""

Thanks for your comment, JdeBP. The documentation has a lot of information, indeed.

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.