As a shared hosting company, it is nowadays almost required to provide one-click installable web applications to your customers. Packages like Joomla, OS-Commerce and WordPress come to mind.
Providing the installation for this isn’t hard. You can simply copy a directory and redirect. The real problem lies in managing the installed applications. You nor the customer wants to have an outdated version and since you provided the installation you need to provide the upgrade.

The ideal situation would be if Joomla would be installed at a central location, which would be used by all customers. Only configuration files and additional support files would be in the configuration directory. Keeping in mind that you, or at least we, don’t want to set additional limits to our customers, support files include additional languages, modules, etc.

I was at a PHP barbecue yesterday, where Johan Janssen of Joomla was speaking. Afterwards I took this problem up with him. He basically said that it wasn’t possible with v1.0 and a bit possible with v1.5, to which I of course gave that standard overconfident answer that nothing is impossible.

The way I wanted to implement this was by overwriting file functions like fopen, file_exists and is_writable using runkit and adding include paths. But after having a good hard look at the source code I had to come to the conclusion that the initial plan wasn’t going to work, well at least not completely.
First of all files are specified with their absolute path and since include isn’t a real function and therefor can’t be renamed, supporting multiple module directories would be a problem. Even Joomla v1.5, where different paths are defined per type (eg. config path, module path), it would be difficult to implement this.
It became clear to me that I needed to look beyond the scope of PHP to tackle this problem. Especially if I wanted to come up with a general solution for all webapps, not only Joomla.

When I was working at Bean IT, we ware looking at a way to re-using projects without having to apply changes to several different directories. The only problem was that the projects ware almost the same, but needed to have additional or modified files. We first though off simply applying all changes in all projects and than use a configuration file, but this quickly became a mess. We next come up with a way to overlay of directories using UnionFS mounts. In the end we decided that the more common solution, to use the diff and patch functionality in SVN was the best way to go.

Although UnionFS wasn’t the best answer for Bean IT, it would be an excellent solution to the webapp problem. Looking on the web, I found that UnionFS had a much appeased successor called aufs. With aufs you can mount one read/write directory, which lays on top of one or more read-only directory. When you open a file, the system will first try to find the file in the read-write directory, when it doesn’t exists it tries the read-only directories. When a file, which is read from the read-only dir, is modified and saved, it is not written back to its original directory, but instead it is saved in the read/write dir. Deleting a file in the read-only dir works differently as well. Instead of actually deleting the file, as special white-out file is saved in the read/write directory and the file isn’t available anymore in the aufs mount.

Using aufs the whole problem seems to be able to be solved nicely. I made a test setup where I have a clean install of Joomla in /usr/share/webapps/joomla. The joomla directory is made world read and writable, but the /usr/share/webapps directory is not executable, so normal users can’t reach the Joomla dir. An empty dir (as rw) and the Joomla directory (as ro) are mounted on the webroot directory, after which I simply run the web installation. The configuration file is written to the rw dir and all works well.

Just to give the step by step commands:
- Download the files and install aufs as descripted at the aufs website. To test, just install it as kernel module (make -f local.mk).
- Download and unpack Joomla to /usr/share/webapps/joomla
- chmod ugo+rwX /usr/share/webapps/joomla -R
- chmod go-x /usr/share/webapps
- mkdir /var/www/my-site/webroot /var/www/my-site/.webroot.rw
- chown www-data.www-data /var/www/my-site -R
- mount -t aufs -o dirs=/var/www/my-site/.webroot.rw/:/usr/share/joomla=ro none /var/www/my-site/webroot
- Add a virtual host with /var/www/my-site/webroot as document root and restart apache
- Install joomla as normal

Setting up Joomla like this give you the possibility to provide webapps like Joomla whith a good set of modules already installed to the customers, without taking away the possibility for them to customize. And it only took one kernel patch/module. Isn’t the world wonderfull… :p