HTTP Server (Apache2)

nolink|

This page describes a method to compile the Apache 2.2 (2.4) server on a debian wheezy platform, preparing it to be used in conjunction with php-farm, so to let one choose a specific php version to be run for each virtual host served through the Apache server.



Download the latest apache2 version

Go to http://httpd.apache.org/download.cgi and select the desired version, we'll stick to 2.2.x version for compatibility reasons (2.2.27 as of this writing), 2.4 seaming to break some configurations used here. For better performance, you may want to select a mirror close to your location at http://www.apache.org/mirrors/.
For safety reasons you might want to verify the sha1 checksum of the downloaded file.

$ cd /usr/src/
$ sudo wget http://apache.cu.be/httpd/httpd-2.2.27.tar.gz
$ sha1sum httpd-2.2.27.tar.gz | grep '23a17a1096c9fa2b12aaaa7893fd10a374ee2f56'
23a17a1096c9fa2b12aaaa7893fd10a374ee2f56  httpd-2.2.27.tar.gz

Apache 2.4

$ cd /usr/src/
$ sudo wget http://apache.cu.be//httpd/httpd-2.4.12.tar.gz
$ sha1sum httpd-2.4.12.tar.gz | grep '0937fa7867a3d4421fd290dcc82e753977f96dca'
0937fa7867a3d4421fd290dcc82e753977f96dca  httpd-2.2.27.tar.gz

If you get no output from the sha1sum command you should really download from another location !

We will now extract the archive:

$ sudo tar xzf httpd-2.2.27.tar.gz

Apache 2.4

$ sudo tar xzf httpd-2.4.12.tar.gz

Configure and compile

Let's now configure the options we want for our apache2 install, the options specified here are specifically crafted to suit our later Phpfarm installation. The important options regarding Phpfarm are:

  • enable-so
  • enable-suexec
  • enable-suexec-caller=daemon – You can change this according to which user your apache runs under.

The other parameters are:

  • prefix=/usr/local/apache2 tells apache where to install all the files needed. In this case we are installing apache to /usr/local/apache2 directory.
  • enable-mods-shared=all tells apache to compile all modules as dynamic shared modules. We can then enable these modules in httpd.conf file, via the LoadModule directive.
  • enable-mod-rewrite tells apache to enable mod rewrite.
  • with-mpm=prefork uses the default, most compatible, Multi-Processing Module. You could change this to worker for a speedier, threaded model.
$ cd /usr/src/httpd-2.2.27/   # /usr/src/httpd-2.4.12/
$ sudo ./configure \
  --prefix=/usr/local/apache2 \
  --with-included-apr \
  --enable-mods-shared=all \
  --enable-so \
  --enable-mod-rewrite \
  --enable-suexec \
  --with-suexec-caller=daemon \
  --enable-suexec=shared \
  --with-mpm=prefork
$ sudo make
$ sudo make install

Possible errors

At configure or make time you might encounter some errors based on your activated options and the available libraries on your system, here are a few examples:

mod_deflate

mod_deflate has been requested but can not be built due to prerequisite failures
$ sudo apt-get update
$ sudo apt-get install zlib1g-dev

Bundled APR

error: Bundled APR requested but not found at ./srclib/.

This one is a bit trickier, you need to go to http://apr.apache.org/download.cgi and download the latest apr and aprutil libraries, then put the files in you apache's installer directory under /path/to/apache/installer/srclib/, and extract them. Finally you need to change the extracted directories names, removing the version number:

$ cd /usr/src/httpd-2.2.27/srclib
$ wget http://apache.cu.be/apr/apr-1.5.1.tar.gz
$ wget http://apache.cu.be/apr/apr-util-1.5.4.tar.gz
$ tar xfz apr-1.5.1.tar.gz
$ tar xfz apr-util-1.5.4.tar.gz
$ mv apr-1.5.1 apr
$ mv apr-util-1.5.4 apr-util

pcre-config for libpcre not found

pcre-config for libpcre not found

You'll also need to download the library, this time from ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/, select the latest version and download it, extract, configure and make it:

$ cd /usr/src/
$ wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.35.tar.gz
$ tar xzf pcre-8.35.tar.gz
$ mv pcre-8.35 pcre
$ cd pcre/
$ sudo ./configure
$ sudo make
$ sudo make install

You need a C++ compiler for C++ support

Install the g+.+ package:

$ sudo apt-get install g++

After you fixed the errors, go back to your apache installer's directory and relaunch ./configure, make and make install…

Test your Apache Installation

First make sure you can access your installation machine, from your host system do:

> ping ip.of.your.install

In a browser application, go to http://ip.of.your.install, you should get a message like: Unable to connect

Startup apache2:

sudo /usr/local/apache2/bin/apachectl -k start

If at runtime you get an error of type error while loading shared libraries: libpcre.so.1:

$ cd /lib/x86_64-linux-gnu
         [i386-linux-gnu]
$ sudo ln -s libpcre.so.3.13.1 libpcre.so.1

In your browser application, go to http://ip.of.your.install, you should get a message like: It works!



Debian apache2.2-common

The global apache2 configuration can rapidly become quite complex.

Since the Debian sources offer a nicely pre-configured environment, grouping most configuration files under /etc/apache2 and allowing usage of the a2ensite, a2dissite, a2enmod, a2dismod, a2enconf, a2disconf and a2query scripts (located in /usr/sbin/). For simplicity we'll install the apache2.2-common package.

You can have a glance at the files that will get installed here on the Debian Packages Website.

$ sudo apt-get install apache2.2-common

Apache Multi-Processing Module

As we chose the prefork MPM during configuration, let's install the corresponding module, note that this operation will also start the web server:

$ sudo apt-get install apache2-mpm-prefork
...
Setting up apache2-mpm-prefork (2.2.22-13+deb7u1) ...
[ ok ] Starting web server: apache2.

You might get a failure at this point, reporting something like:

apache2(98)Address already in use: make_sock: could not bind to address [::]:80
(98)Address already in use: make_sock: could not bind to address 0.0.0.0:80
no listening sockets available, shutting down
Unable to open logs
Action 'start' failed.
The Apache error log may have more information.

DO NOT WORRY: simply restart your VM and everything should be up and running fine…



suEXEC can be a bit fiddly in that the document root (the parent folder for all web content) is generally set at compile-time. This has led to numerous guides giving instructions for retrieving the Apache source and reconfiguring and recompiling the suEXEC module to set /home as the document root instead of /var/www. Fortunately for us, Debian provides a custom suEXEC package, apache2-suexec-custom, which has been modified to permit post-compilation reconfiguration by way of a simple configuration file.

> sudo apt-get install apache2-suexec-custom

The default configuration file for apache2-suexec-custom is /etc/apache2/suexec/www-data. The first line of the file can be changed to use a non-default document root.

Please note that the file name (here www-data) is corresponding to the user suexec will run as. You might want to create other files, or rename the existing one, to fit your current configuration.



We also need the fcgid module to run different PHP versions using Phpfarm.

sudo apt-get install libapache2-mod-fcgid


$ sudo a2enmod rewrite
$ sudo a2enmod suexec
$ sudo a2enmod include
[$ sudo a2enmod fcgid]     (this should be automatic with fcgid installation)
$ sudo service apache2 restart


The following applies to VirtualBox VMs only

The virtual machine we're building is aimed at containing a complete and flexible development environment. Although, in order to allow easier edition of your websites sources files, they should not reside inside it, but rather in a directory at your host system level.

To achieve this we'll use a Shared Folder pointing to a directory on your host's filesystem and mounted as /var/www inside the VM.

Let's say that we want our web files in /home/<username>/Documents/webdev/www, you can use VirtualBox's GUI or CLI to prepare the shared folder:

Using the GUI

Create the desire directory.
Select your Virtual Machine in VirtualBox Manager window's left column, then click on the “Shared Folder” tab. Click the “plus” icon on the right of the popup window. Then select the folder to share and give it a name (we'll call it www-share), check the “Make permanent” box.

direct&200 |

Using the CLI

Type the following command in your host's terminal (where ApacheDev is your VM's name):

$ mkdir -p /home/<username>/Documents/webdev/www
$ VBoxManage sharedfolder add "ApacheDev" --name "www-share" --hostpath "/home/<username>/Documents/webdev/www"

On your guest VM, try mounting the newly created shared folder using:

> sudo mount -t vboxsf <www-share> </path/to/montpoint>

In case at this point you run into a mount error of type:

mount: unknown filesystem type 'vboxsf'

You need to install the VirtualBox Guest Additions, see the Install VirtualBox Guest Additions section on this wiki.



The whole thing here will be to setup permissions so that we will be able to store all our development files in directories accessible via the host's file system, i.e. in regular folders on our host machine, and share those folders as so to have apache, suexec (and later mysql) access them inside the guest VM with the correct access rights.

Create the "suexec" User

First off we'll need to create a user inside the VM which will be used to execute all cgi scripts, this means, in our case, execute PHP.
In a production environment, we could have different users executing cgi through suexec for security reasons. For the purpose of our development environment, we'll satisfy ourselves with just one user, which we'll name “suexec”. We'll need to know this user's user id (uid) and group id (gid).

Inside your VM:

> useradd suexec
> id suexec
uid=1001(suexec) gid=1001(suexec) groups=1001(suexec)

Make the apache user part of the suexec group

We also need to have the user which apache is running as be part of the same suexec group.
First let's identify the user apache is running as. Start by making sure apache is running, then find out the user it is running as:

In your VM:

> service apache2 start
[....] Starting web server: apache2httpd (pid 3037) already running
. ok

> ps aux | grep apache
root      3037  0.0  0.4  81316  4296 ?        Ss   Oct30   0:06 /usr/sbin/apache2 -k start
www-data  3041  0.0  0.2  81244  2116 ?        S    Oct30   0:02 /usr/sbin/apache2 -k start
www-data  3043  0.0  0.2  81348  2284 ?        S    Oct30   0:00 /usr/sbin/apache2 -k start
www-data  3044  0.0  0.2  81348  2284 ?        S    Oct30   0:00 /usr/sbin/apache2 -k start
...

The first column indicates the user name “www-data” which apache is running as.

Let's make this user part of the suexec group in your VM:

> usermod -a -G suexec www-data

Setup Shared Folders Mount Options

We'll come back to this later for the MySQL config but for the moment we'll stick with our web development directories.

Using /etc/fstab

We willd add the following to the /etc/fstab file and have the VM automount our shared folder at boot time:

$ sudo nano /etc/fstab

ADD:
# automount www-share as web root
www-share   /var/www   vboxsf   defaults  0   0

Unfortunately doing so the shared folder is owned by root:root in this case. This would become a problem as soon as we'll try to run any PHP script with suexec.

Thus we need to have our shared folder mounted with suexec as its owner
We'll update our /etc/fstab using the uid/gid that we identified for our suexec user earlier:

$ sudo nano /etc/fstab

CHANGE:
# automount www-share as suexec
www-share   /var/www   vboxsf   defaults,uid=1001,gid=1001  0   0

Mount command options

Thus, we can mount our shared folders owned by a specific user and group by issuing the following command:

$ sudo mount -t vboxsf www-share -o rw,gid=1001,uid=1001 /var/www
OR
$ sudo mount -t vboxsf www-share -o rw,dmode=777,gid=1001,uid=1001 /var/www

Note that the “original” permissions, the ones that are set at the host's filesystem level, will be applied, the dmode option can be used in case you also need to update the directories permissions at mount time.

Other available options are:

rw         mount read write (default)
ro         mount read only
uid       =<arg> default file owner user id
gid       =<arg> default file owner group id
ttl       =<arg> time to live for dentry
iocharset =<arg> i/o charset (default utf8)
convertcp =<arg> convert share name from given charset to utf8
dmode     =<arg> mode of all directories
fmode     =<arg> mode of all regular files
umask     =<arg> umask of directories and regular files
dmask     =<arg> umask of directories
fmask     =<arg> umask of regular files


Since we installed the apache2.2-common package, most of the apache configuration files are located under the /etc/apcahe2 directory (inside the VM).

Configuring a new virtual host becomes quite simple as it suffice to add a new configuration file inside /etc/apache2/sites-available/ and issue an a2ensite command as explained hereunder.

Create the Virtual Host Directory

On the host's filesystem
Create the virtual host directory inside the configured shared folder:

$ mkdir -p /home/<username>/Documents/webdev/www/my-website/web
$ mkdir /home/<username>/Documents/webdev/www/my-website/log

Create a Virtual Host Configuration File

Login to your apache development VM and create a new virtual host configuration file under /etc/apache2/sites-available/, then activate it using the a2ensite command and restart the apache2 service as follow:

$ sudo nano /etc/apache2/sites-available/<vhostname>

CONTENT:
<VirtualHost *:80>
  ServerName <vhostname>
  ServerAlias <vhostname>
  ServerAdmin webmaster@<vhostname>
  DocumentRoot /var/www/<vhostname>/web/

  <IfModule mod_fcgid.c>
    SuexecUserGroup suexec suexec
    #PHP_Fix_Pathinfo_Enable 0
    <Directory /var/www/<vhostname>/web/>
      Options +ExecCGI
      AllowOverride All
      AddHandler fcgid-script .php
      FcgidWrapper /var/www/php-fcgid/php-cgi-5.4.4 .php
      Order allow,deny
      Allow from all
    </Directory>
  </IfModule>

  ErrorLog /var/www/<vhostname>/log/error.log
  CustomLog /var/www/<vhostname>/log/access.log combined
  ServerSignature Off
</VirtualHost>

You probably noticed that this configuration file allows you to specify the PHP version you'd like to execute for the specified vhost using phpfarm (follow this link to learn how to install php-farm).
We did as well specify the location where the apache logs are to be stored. We chose to have them stored under the /var/www/<vhostname>/log directory so they will be available straight from the host's filesystem (no need to login into the VM to consult them).

Apache 2.4

In case your installing Apache 2.4, the following code needs to be modified according to the directives found on the Apache website:

Replace:

Order allow,deny
Allow from all

With

Require all granted

Activate the New Virtual Host

$ sudo a2ensite <vhostname>
$ sudo service apache2 reload

If the /etc/apache2/000-default file is present in your VM, you should disable it with the following command in order to have everything working as expected:

$ sudo a2dissite 000-default
$ sudo service apache2 reload

Add Your Website to your Host's /etc/hosts File

As apache's virtual hosts are based on the domain name you type to access them, we still need to “link” the chosen web name to the VM's IP address in the host OS.
This is achieved by adding an entry into the /etc/hosts file on your host OS as follow:

$ sudo nano /etc/hosts

ADD:
# Apache development VM virtual hosts
172.20.20.2 <vhostname> <another-vhost>

You can add as many virtual hosts names as you need, simply separating each one with a space on the line following your development VM's IP address.


Make sure everything is running as expected

To make sure everything is running as expected, i.e. that Apache is serving your web pages and that your selected PHP version is well executed on your virtual host, simply create an info.php file at your virtual host's root (here /home/<username>/Documents/webdev/www/<vhostname>/web), and write those two lines in this file:

> nano /home/<username>/Documents/webdev/www/<vhostname>/web/info.php

<?php
  phpinfo();

Then access this page from a web browser using http://<vhostname>/info.php, you should see a page summarizing your installed php config.



This is already explained in the initial VM setup



Pages Caching


The above configuration worked seamlessly for months, and then, all of a sudden, the updates that were made on the files were not available on browser's reload !
This means, when editing a file and trying to refresh the corresponding page in the development environment, the “old” version of the page, the first one served after the apache2 start, would be delivered over and over, no matter if its file code had been modified or not. At first it seemed obvious that it would be an Apache cache issue, but after making sure the mod_cache, mod_disk_cache and mod_mem_cache modules were completely disabled… It didn't fix the issue!

Even reloading/restarting the apache2 service couldn't help, only a full server reboot would do the trick :-/

Setting a short cache time

First thing, we can try and set the apache2 caching time to only one second. This can be done by making sure the apache's “expires” and “header” modules are enabled, then set a very short caching time in .htaccess:

> sudo a2enmod expires headers
> sudo service apache2 restart
> nano /your/site/home/.htaccess
<FilesMatch "\.(htm|html)$">
  ExpiresActive On
  ExpiresDefault A1
  Header append Cache-Control must-revalidate
</FilesMatch>

Using the “FilesMatch” filter will allow to determine what files are affected by the caching policy, in case some programmatically generated (i.e: .php) files are already bearing the cache restriction header…

System level caching

This didn't completely resolved the problem on my configuration.
It turned out the problem came from the VM Linux system itself, it was somehow caching the operation. Luckily I found this post on ServerFault, coming with the sync; echo 3 > /proc/sys/vm/drop_caches command that effectively solved this issue. It is possible to “manually” launch the command repeatedly using the watch -n command to clean the system cache every second:

> watch -n 1 'sync; echo 3 > /proc/sys/vm/drop_caches'

We could also have a bash script running an endless loop every second, avoiding the need of the manual launch of the watch command. To this purpose, we'll create a shell drop_caches.sh script file and put in an @reboot cron task (following commands assumed as root):

> nano /etc/init.d/drop_caches.sh

PASTE:
#!/bin/bash
sync; echo 3 > /proc/sys/vm/drop_caches

> chmod +x ~/scripts/drop_caches.sh
> crontab -e

PASTE:
@reboot /root/scripts/drop_caches.sh

> reboot

To make sure that the script is well running after reboot:

> ps aux | grep [c]aches
root      2260  0.0  0.0   4184   576 ?        Ss   02:50   0:00 /bin/sh -c /root/scripts/drop_caches.sh
root      2266  0.3  0.1  10768  1412 ?        S    02:50   0:00 /bin/bash /root/scripts/drop_caches.sh