shell environment variables in "include"-directive not working

Brian H. lists at ruby-forum.com
Sat Feb 23 23:02:22 UTC 2013


Just wanted to respond that I had the similar need, and hopefully a 
better solution. We too have dev, staging, prod, and the configurations 
are similar, but not identical.
We have hundreds of servers, and the variances in files means we need to 
have a much longer runway for new sysadm recruits to get up to speed, 
and increases the opportunity for errors caused by divergence - 
especially in active/active or active/passive configurations in 
production.

Next - the link to sed which is a HORRIBLE idea to my OCD brain.  sed is 
a line parser, it fundamentally doesn't understand the hierarchy of an 
nginx conf file(s). The opportunity for something to go horribly 
horribly wrong and be very difficult to troubleshoot (especially with 
high degrees of automation/scripting in other areas of our platform) 
scares the crap out of me. Using sed to parse old style unix files where 
everything is on a single line and all lines are identical = great, 
using it to parse a nested configuration file where each line is 
different is a horrid idea (even with excellent naming conventions).
I am actually not aware of any valid NGINX hierarchy parser, and since 
it uses a very non standard, highly complex syntax I think it would be 
reasonably challenging to write one which could read, modify, write back 
the same file with comments, etc.  (I bet a lot of people do)

AND -- something as a simple __HOSTNAME__ or #IFHOSTNAME would be 
*amazingly* useful for a variety of situations.
I also wanted to share to others who may also have the same issues why 
user defined environment variables are a horrible idea too and why the 
devs are so resistant to them.   When trying to hot-swap executables 
since the environment won't carry across pids -- this is a cool feature 
nginx has, and using environment variables would break that.
So stop asking for environment variables -- instead we should be 
thinking about a few well known variables that can be interpolated at 
config parsing time would be useful for those of us with hundreds of 
servers to manage the 1-2% variances between each servers without 
needing an elaborate custom build script. one config file to bind them 
all and KISS.

**SO** I may write a plugin to do that in the future, but alas, no time. 
So I submit the slightly ghetto work around I devised.

First use host file trickery (this is IMHO pretty common for 
dev/prod/staging) to alias well known role based names "ex: api, www, 
etc"

Use symlinking with hostname to include the proper files based on 
hostname. Modify your init.d script so it links, or touches empty files 
when a corresponding file doesn't exist.

I'm not going to provide examples here because inevitably your 
environment will be different than mine, but I can tell you that nginx 
will load a empty (zero byte) include file with no issues.
Of course environment variables like hostname in a shell script is 
trivial.

So when you bake it all together - in the nginx.conf file:

include "some-role.conf"
include "lotsofcustom-roles/*.conf"
include "yetanother-role.conf"

** those includes point at symlinked or zero byte files.

In the /etc/init.d/nginx script do something like:

/bin/rm -f $NGINXROOT/conf/some-role.conf
/bin/rm -f $NGINXROOT/conf/lotsofcustom-roles
/bin/rm -f $NGINXROOT/conf/yetanother-role.conf
if [ -f "$NGINXROOT/conf/some-role-$HOSTNAME.conf" ] ; then
   ln -s "$NGINXROOT/conf/some-role-$HOSTNAME.conf" 
$NGINXROOT/conf/some-role.conf"
else
   touch $NGINXROOT/conf/some-role.conf
fi
if [ -d "$NGINXROOT/conf/lotsofcustom-roles-$HOSTNAME" ] ; then
   ln -sd "$NGINXROOT/conf/lotsofcustom-roles-$HOSTNAME" 
$NGINXROOT/lotsofcustom-roles"
else
   mkdir $NGINXROOT/conf/lotsofcustom-roles
   touch $NGINXROOT/conf/lotsofcustom-roles/nothing-to-see-here.conf
fi
if [ -f "$NGINXROOT/conf/yetanother-role-$HOSTNAME.conf" ] ; then
   ln -s "$NGINXROOT/conf/yetanother-role-$HOSTNAME.conf" 
$NGINXROOT/conf/some-role.conf"
else
   touch $NGINXROOT/conf/yetanother-role.conf
fi

Obviously this is highly dependent on exactly what you want to 
accomplish, but I think it strikes a much nicer balance than use a sed 
machete to hack through a config file using regular expressions it 
doesn't understand and accidentally clobbering something you didn't 
intend to.

Regards,

-Brian Horakh
Chief Technical Guy
anyCommerce





Maxim Dounin wrote in post #911875:
> Hello!
>
> On Thu, May 13, 2010 at 12:49:21AM +0200, Markus Grobelin wrote:
>
>> Hy everybody,
>> i'm doing my first steps with nginx/0.8.36 and trying to get *NIX
>> shell environment variables working inside the configuration files.
>> Sadly, it's seems they aren't working inside the
>> "include"-directive! :(
>
> nginx doesn't have syntax for expanding environment variables in
> configuration file.  Syntax $var used for runtime per-request
> variables (supported by some directives, support explicitly noted
> in directive descriptions).
>
> [...]
>
>> The [emerg] indicates, that the $INSTANCE environment variable isn't
>> expanded, whereas the "user" and "pid" directive doesn't raise an
>> exception??
>
> Because there is no syntax error in user "$USER" and config parser
> has nothing against it.  As you aren't running as root nginx
> just prints warning about being non-root and forgets about it.
> Under root you should see:
>
> [emerg]: getpwnam("$USER") failed in /path/to/nginx.conf:line
>
> (unless you actually have "$USER" in your /etc/passwd)
>
> Similar thing with pid.  It's syntactically correct and will only
> produce error when nginx will try to create pid file.  If you
> happen to cleanup other critical config errors you should see
> something like this on startup:
>
> [emerg]: open() "/nginx/$INSTANCE/run/nginx.pid" failed (2: No such file
> or directory)
>
> (again, unless you actually have "/nginx/$INSTANCE/run/" directory)
>
> Maxim Dounin

-- 
Posted via http://www.ruby-forum.com/.



More information about the nginx mailing list