84

Is it possible to use variables in Apache config files?

For example, when I'm setting up a site with Django+WSGI, the config file might look like:

<Directory /path/to/foo/>
    Order allow,deny
    Allow from all
</Directory>
Alias /foo/static /path/to/foo/static
WSGIScriptAlias /foo /path/to/foo/run_wsgi

And I'd like to turn the '/path/to/foo' into a variable so it only needs to be defined in one place. Something like:

Variable FOO /path/to/foo
…

Thanks!

7 Answers 7

77

You could use mod_macro, which has been included in Apache httpd since version 2.4

Before that it had to be installed separately, see mod_macro. For example on Debian: apt-get install libapache2-mod-macro; a2enmod macro.

Example configuration

/etc/apache2/conf.d/vhost.macro

<Macro VHost $host $port>
  <VirtualHost $host:$port>

    ServerName $host
    DocumentRoot /var/vhosts/$host

    <Directory /var/vhosts/$host>
      # do something here...
    </Directory>
  </VirtualHost>
</Macro>

/etc/apache2/sites-available/vhost.mysite.com

Use VHost vhost.mysite.com 80
3
  • 1
    Ah, that looks like what I need. Shame it isn't built in… But I guess I can live. Thanks! Sep 12, 2009 at 23:58
  • 5
    @SpoonMeiser This module is integrated into Apache HTTP Server from version 2.4.6. httpd.apache.org/docs/current/mod/mod_macro.html
    – Ludwig
    Apr 30, 2014 at 7:57
  • In your example, you have the same path coded for DocumentRoot /var/vhosts/$host and <Directory /var/vhosts/$host>. I have similar cases, where I'd want to define hostpath=/var/vhosts/$host, and use DocumentRoot ${hostpath} and <Directory ${hostpath}>. Is there no good way to do this? Or should I use Define hostpath /var/vhosts/$host and UnDefine hostpath after I'm doing using the variable in the macro?
    – RjOllos
    Nov 22, 2019 at 17:37
37

Much simpler using Define keyword. See Define Directive.

Define RVM_ROOT /opt/rvmdir/gems
Define RUBY_18 ruby-1.8.7-head

...

SetEnv GEM_HOME ${RVM_ROOT}/${RUBY_18}@typo55
SetEnv GEM_PATH ${RVM_ROOT}/${RUBY_18}@typo55:${RVM_ROOT}/${RUBY_18}@global
3
  • 5
    Note that The variable is always globally defined and not limited to the scope of the surrounding config section. It probably means (I didn't test it for now) that, if you have multiple vhosts, you can't use the same variable (with a different value) for each. Jul 4, 2019 at 8:41
  • @Pierre-OlivierVares Correct, see them as constants. this is why I use CAPITAL letters. I define them globally outside of the VirtualHost
    – Mathieu J.
    Jul 4, 2019 at 10:43
  • A test with Apache/2.4.46 shows clearly that Define defines variables, not constants. Redefining the same name works without error, changing the current value of the variable. So, using Define and Include to define things like virtual hosts works nicely, as shown by a simple test. Macros should work, too (didn't test them, though). Jan 5, 2021 at 15:39
15

You can enable or disable bits of configuration with IfDefine but that probably won't do what you want. Instead, You can set environment variables in your Apache init script to access within the configuration. For example, adding:

HOSTNAME=$(hostname)

to /etc/init.d/httpd (before the line that calls httpd!) on a RHEL machine passes the machine's hostname in as a variable. It doesn't have to be the output of a command -- anything that sets a variable in the environment which launches httpd is fine. Variables can be used in the configuration like so:

[root@dev ~]# cat /etc/httpd/conf.d/test.conf
Header set X-Hostname ${HOSTNAME}

[root@dev ~]# GET -Sed http://localhost
GET http://localhost --> 200 OK
Connection: close
Date: Fri, 11 Sep 2009 20:47:13 GMT
Server: Apache/2.2.3 (Red Hat)
Content-Length: 525
Content-Type: text/html;charset=ISO-8859-1
Client-Date: Fri, 11 Sep 2009 20:47:13 GMT
Client-Peer: 127.0.0.1:80
Client-Response-Num: 1
Title: Index of /
X-Hostname: dev.local

Of course, you're not restricted to the Header directive. The variables can be used anywhere, like <Directory ${FOO}> etc.

If you don't like this (and it's not that nice..) you can generate a configuration from a template using m4 or some other template language.

ADDITIONAL:

Hrm, one way to make it better would be to store all the variables in an external file, perhaps /etc/httpd/conf/variables.txt:

FOO=/path/to/dir
ROLE=development

and then include these into your Apache init.d script with:

. /etc/httpd/conf/variables

before calling httpd. Still not brilliant but at least it separates the startup script and variables.

1
  • 11
    A better (and cleaner) place for these environment variables would be /etc/sysconfig/httpd (RedHat, CentOS) or /etc/apache2/envvars (Ubuntu/Debian). Some environment variables are there already. Apr 22, 2011 at 23:41
9

You can use system environement variables with mod_env and the PassEnv directive. See here

Example for debian:

Add your variable to /etc/apache2/envvars (this file is used by apache2ctl to define variables)

...
export APACHE_PID_FILE=/var/run/apache2.pid
export HOSTNAME=$(hostname)

Pass your variable into apache config

PassEnv HOSTNAME

You can then access the system environment variable like if it was an apache variable.

Header set Served-By %{HOSTNAME}e
2
  • 1
    thanks very much - although this didn't provide the answer for me on apache 2.2 centos 6.4 - it did point me in the right direction +1
    – danday74
    Apr 14, 2016 at 14:57
  • This requires mod_define, not loaded in apache2.2 by default.
    – Thomas BDX
    Oct 18, 2018 at 19:18
3

I had the same problem and, after some research, the solution for Apache 2.x that exactly solved it for me (and nothing more) was this:

http://people.apache.org/~rjung/mod_define/

Beware that after unpacking you should build it like so (the install part of the docs seem to have forgotten to adhere to apache2?):

apxs2 -cia mod_define.c

Then create /etc/apache2/mods-available/define.load:

LoadModule define_module /usr/lib/apache2/modules/mod_define.so

After that, enable the module using a2enmod like you normally would.

The docs in the link above show how to use it. Now you can very simply define stuff and use it directly, all within the same apache2 config.

1
  • 1
    In case this isn't clear, this exact same functionality is available by default in Apache 2.4.
    – ColinM
    May 7, 2013 at 22:16
2

unbelievable but on httpd 2.2 on centos 6.4 this works

export env vars in /etc/sysconfig/httpd

export mydocroot=/var/www/html

then simply do this ...

<VirtualHost *:80>
  DocumentRoot ${mydocroot}
</VirtualHost>

then finally ....

service httpd restart;
1
  • this is probably because (some of) /etc/sysconfig/httpd content goes into httpd -D (the equivalent to the define directive) which define apache variables.
    – user246890
    Feb 26, 2019 at 13:27
1

You may want to look into mod_passenger for apache which can also host django apps. We use it with great success. All you need to do in the vhost is, hmm, exactly nothing. Only thing you need is to create a "public" dir in the application root and create symlinks in "public" to your static directories like "media" (this will boost static serving performance) and point your DocumentRoot to it.

Then place the following file in "public/../passenger_wsgi.py":

import sys, os
current_dir = os.path.dirname(os.path.abspath(__file__))
sys.path.append(current_dir)
sys.path.append('/PATH/TO/PACKAGES') # optional
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()

Fire up your browser: It works!

0

You must log in to answer this question.

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