HTTP Server (Apache2)
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.
Compile Apache2
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!
Configure Apache2
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…
Install apache suEXEC
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.
Install mod_fcgid
We also need the fcgid module to run different PHP versions using Phpfarm.
sudo apt-get install libapache2-mod-fcgid
Enable all Required Modules
$ sudo a2enmod rewrite $ sudo a2enmod suexec $ sudo a2enmod include [$ sudo a2enmod fcgid] (this should be automatic with fcgid installation) $ sudo service apache2 restart
Create the Shared www Folders
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.
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.
Setting Permissions and Mount Options
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
Virtual Host Setup
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.
Fixed IPs
Tricks
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