====== HTTP Server (Apache2) ====== {{:vms:webdev:apache-logo.png?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. ----- ===== 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 [[https://packages.debian.org/wheezy/amd64/apache2.2-common/filelist|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//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. {{ :vms:webdev:vbox-sharedfolder.png?direct&200 |}} === Using the CLI === Type the following command in your host's terminal (where ApacheDev is your VM's name): $ mkdir -p /home//Documents/webdev/www $ VBoxManage sharedfolder add "ApacheDev" --name "www-share" --hostpath "/home//Documents/webdev/www" On your guest VM, try mounting the newly created shared folder using: > sudo mount -t vboxsf 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 [[vms:python:django#install_virtualbox_guest_additions| 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 = default file owner user id gid = default file owner group id ttl = time to live for dentry iocharset = i/o charset (default utf8) convertcp = convert share name from given charset to utf8 dmode = mode of all directories fmode = mode of all regular files umask = umask of directories and regular files dmask = umask of directories fmask = umask of regular files ----- ===== Virtual Host Setup ===== ----- Since we installed the [[vms:webdev:apache#Debian apache2.2-common|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 [[vms:webdev:apache#Create the Shared www Folder|configured shared folder]]: $ mkdir -p /home//Documents/webdev/www/my-website/web $ mkdir /home//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/ CONTENT: ServerName ServerAlias ServerAdmin webmaster@ DocumentRoot /var/www//web/ SuexecUserGroup suexec suexec #PHP_Fix_Pathinfo_Enable 0 /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 ErrorLog /var/www//log/error.log CustomLog /var/www//log/access.log combined ServerSignature Off You probably noticed that this configuration file allows you to specify the PHP version you'd like to execute for the specified vhost [[vms:webdev:phpfarm|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//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 [[http://httpd.apache.org/docs/trunk/upgrading.html#access|directives found on the Apache website]]: Replace: Order allow,deny Allow from all With Require all granted ==== Activate the New Virtual Host ==== $ sudo a2ensite $ 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 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//Documents/webdev/www//web//), and write those two lines in this file: > nano /home//Documents/webdev/www//web/info.php Then access this page from a web browser using [[http:///info.php]], you should see a page summarizing your installed php config. ---- ===== Fixed IPs ===== ----- ++++This is already explained in the initial VM setup| In order to have a coherent, and permanent, way of accessing our development environment, we'll set a fixed IP for our virtual machine, as well as a corresponding alias on the laptop/workstation. This is achieved by editing the **/etc/network/interfaces** file. You are free to choose whatever configuration you see fit for your needs. In the present example, we'll select the less used 172.16.0.0/12 private network ([[http://en.wikipedia.org/wiki/Private_network]]) because we're deploying this development VM on a laptop computer that gets it's main IP address from DHCP in different environments.\\ To avoid potential IP addresses conflicts as much as possible, we'll (arbitrarily) go and use the 172.20.20.0/8 range for our local virtual systems. ==== Set the host's IP alias ==== We won't go into the details of setting up the host's IP alias here as the way to do this greatly depends upon your operating system. Please refer to your OS documentation in order to learn how to add an IP alias to your main network interface through your OS GUI. To achieve this manually on Debian, you'll have to edit the **/etc/network/interfaces** file and insert something like the following: $ sudo nano /etc/network/interfaces ADD: # Alias for Vbox guests on main ethernet interface auto eth0:1 iface eth0:1 inet static name Vbox Ethernet alias LAN card address 172.20.20.1 netmask 255.255.255.0 broadcast 172.20.20.255 network 172.20.20.0 Then bring up the eth0:1 interface: $ sudo ifup eth0:1 ==== Set the VM's IP ==== Setting a static IP for your VM is exactly the same as described for your host, just pay attention not to set twice the same IP address for two VM that will run at the same time as they might conflict. Note that we create IP aliases on the main interface, keeping the general DHCP setting so that the VM still can reach the Internet if necessary (for package update for example). $ sudo nano /etc/network/interfaces ADD: # Alias for Vbox guests on main ethernet interface auto eth0:1 iface eth0:1 inet static name Vbox Ethernet alias LAN card address 172.20.20.2 netmask 255.255.255.0 broadcast 172.20.20.255 network 172.20.20.0 Then bring up the eth0:1 interface: $ sudo ifup eth0:1 ==== Check that the Virtual Network is Working ==== From your host, try: $ ping 172.20.20.2 PING 172.20.20.2 (172.20.20.2) 56(84) bytes of data. 64 bytes from 172.20.20.2: icmp_seq=1 ttl=64 time=0.314 ms This indicates that your host and VM can now communicate using the "virtual network", you won't need to check the DHCP allocated IPs each time you restart the VM or when you operate inside a network that you do not control. ----- ++++ ---- ===== 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 [[http://httpd.apache.org/docs/2.2/mod/mod_cache.html|mod_cache]], [[http://httpd.apache.org/docs/2.2/mod/mod_disk_cache.html|mod_disk_cache]] and [[http://httpd.apache.org/docs/2.2/mod/mod_mem_cache.html|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 ExpiresActive On ExpiresDefault A1 Header append Cache-Control must-revalidate 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 [[http://serverfault.com/questions/163894/file-change-on-a-lamp-development-server-not-taken-into-account|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