Apache IfDefine and startup with sysVinit and systemd

Apache IfDefine and startup with sysVinit and systemd

To define a name for use in directives during Apache startup is an easy way to control the behavior of the webserver depending on your environment specifics.

This way you can have different configurations applied according to the context, facts you have or variables you set. It is possible to distinguish between production and development, detected facts, the hostname or a context string.
And you can have your apache config stored in a git repository which is used on two or more webservers to propagate changes easily between hosts.

These are the two use cases I want to look into:

  • having several web servers (doing the same thing) but with different hardware
  • having a development machine and one or more production machine(s) with a slightly different configuration

How would you do this?

Let us first look how we can deal with different hardware

The assumption is that the webservers are providing the same service, have a common code base but differ in terms of hardware: some might have 8, other 16 GB of memory. So your certainly want to tune how many apache processes should run initially and at most.

I admit this scenario isn’t as relevant today as was in the good old times with dedicated servers and long contract periods. But it can be adapted to other use cases.

But back to our task at hand. How do you know how much memory bob has?

Ah, that is easy, right? Because your servers are like pets, not cattle and you know every bit about them 😉

And based on your knowledge you fine tuned the amount of apache processes to start in your configuration.

...

# check whether hostname was given as startup parameter


# if it wasn't make the config fail:
Include conf/hosts-HOSTNAME_NOT_GIVEN.conf
# Hint:
# ~~~~~
# for this to work '/etc/init.d/apache' has to be tweaked like this:
# [...]
# HOST=$(hostname -s)
# [...]
# start|stop|restart|graceful|graceful-stop)
#    $HTTPD -D TBT -D $HOST -k $ARGV
# configtest)
#    $HTTPD -D TBT -t
 


# include host specific config for bob
Include conf/extra/host-bob.conf



# include host specific config for alice
Include conf/extra/host-alice.conf

And that’s for example what is in host-bob.conf, according to his RAM size:

# bob, 8 GB RAM

ServerLimit          256
MaxRequestWorkers    256

The old way using sysVinit

In the old times before systemd this could easily be configured in the init.d startscript.

We lookup the hostname into the HOST variable. Then, we pass the hostname together with the constant “TBT” (it has no special meaning, it is just a random string) to the apache binary.
“TBT” is later used to have an error condition to fail on startup if TBT isn’t set. That’s a safety net if you forgot to use the modified apache init script. Startup would fail and prevent misconfiguration based on the missing host config.

Here’s the excerpt of /etc/init.d/apache with the relevant lines:

...

  # to be able to use host dependant configs apache needs to know the hostname
  # -> we can work with <IfDefine> if we append -D${HOST} to the start cmd

  # do determine the hostname:
  HOST=$(hostname -s)

...

case $ARGV in
  start|stop|restart|graceful|graceful-stop)
     $HTTPD -D TBT -D $HOST -k $ARGV
      ERROR=$?
      ;;
  startssl|sslstart|start-SSL)
      echo The startssl option is no longer supported.
      echo Please edit httpd.conf to include the SSL configuration settings
      echo and then use "apachectl start".
      ERROR=2
      ;;
  configtest)
      $HTTPD -D TBT -D $HOST -t
      ERROR=$?
      ;;

...

  esac

A new aproach with systemd

With systemd everything changes. You can’t apply the same functionality to the apache unit file – it just won’t work.
But fortunately there is the envvars file (at least in Ubuntu, with apache2 packages), the perfect place for our modification:

...

## If you would like to pass arguments to the web server, add them below
## to the APACHE_ARGUMENTS environment.

HOST=$(hostname -s)
export APACHE_ARGUMENTS="-D TBT -D ${HOST}"

It is even simpler because you don’t have to mess with the more complex init script 🙂

Development vs. production with systemd

Dealing with a slightly different configuration depending on whether you are on development or production is easy. You might for example have different SSL-Certificates for dev or prod.

Here we check the hostname and if it matches our development environment (hostname websrv or websrv-vagrant) we can load a modified configuration as described above. Every other host will apply the production configuration.

...

## If you would like to pass arguments to the web server, add them below
## to the APACHE_ARGUMENTS environment.
HOST=$(hostname -s)

case $HOST in
websrv|websrv-vagrant)
STAGE=dev
;;
*)
STAGE=prod
;;
esac

export APACHE_ARGUMENTS="-D ${STAGE}"

Just as an example:

# see envvars:
# STAGE = dev -> development environment

    
    
      # .dev.example.com
      ServerName websrv.dev.example.com

...

     
    


Leave a Reply

Your email address will not be published. Required fields are marked *