Apache Configuration Issues

Trying to set up a new Zend Framework (ZF) website, I struggled once again with getting the setup correct. I learned some lessons, and this post is supposed to help me remember them.

First, the requirements.

1) ZF websites need rewrite rules to force all the urls through index.php so the can be picked apart. Also, ZF websites using the ZF config mechanisms need an APPLICATION_ENV php variable set somewhere in the site configuration, so the website can figure out where it is running and make hosting specific decisions (like, e.g. where the database will be, whether to turn on debugging, etc.).

2) I want to keep the website in a repository, and check it out onto different web-hosts  for testing, development, production. So any configuration stuff which is web-host specific should not be in the repository but in the host configuration files.

3) Although the urls for the ZF website need to be rewritten to index.php, there may be other urls (like phpmyadmin) that should not be rewritten. So the configuration has to allow for this. In particular on some websites (like wmbuck.net) the website itself redirects non-logged in users to the blog (this blog) with a redirect to /blog/. The rules need to allow normal handling of this url (to select /blog/index.php) in the normal way.

The rewrite rules and application environment stuff can be put in an .htaccess file within the DocumentRoot. Most ZF documentation describes doing it this way. But for me, at least the application environment variable can’t be here because everything under DocumentRoot is in the repository. So I want APPLICATION_ENV oregano on one box, APPLICATION_ENV tarragon on another box, and if I put this in .htaccess, and .htaccess is in the repository the file can only have one or the other setting.

The rewrite rules and application environment can also be put into the apache config files, in the VirtualHost container (since I am using VirtualHosts on all these boxes). At least for the APPLICATION_ENV this is far superior. Once it is set up with APPLICATION_ENV tarragon on the tarragon box, it never changes.

The rewrite rules could still go in an .htaccess file,  Maybe this would even be easier, but I chose not to do this. I chose to put the rewrite rules in the apache config files also, I suppose because I think that the rewrite rules are specific to the web-host more than to the web-site. For example, on tarragon and other public internet boxes, I almost always force everything to SSL, so there is a VirtualHost for port 80 that redirects everything to the VirtualHost for port 443. As a result the rewrite rules for doing ZF rewriting need to be applied in the 443 VirtualHost container, and not in the port 80 one. If the rewrite rules are in the .htaccess file they apply in both.

Lesson 1:

Right or wrong, I put the rewrite rules into the apache config files. But it turns out that the rewrite rules need to be written differently if they are in the apache config files. The rewrite rules that show up in various ZF documentation are almost always written as they need to be in the .htaccess file.

The reason it is different has to do with what apache knows when it invokes the rule. When processing the .htaccess file apache has already done all the mapping of urls into the file system, and is already in the DocumentRoot. But when processing a rule in the VirtualHost container, it has not yet done the mapping to the filesystem. Thus the variable REQUEST_URI refers to different things. In .htaccess REQUEST_URI refers to a (potential) filesystem location, with the DocumentRoot on the front (perhaps /var/www/Suzano/patient/list). With the config files REQUEST_URI still refers to what is in the URL (/patient/list). So the rewrite rules have to be different.

In the simple case of the ZF rewrite rules, for example:

RewriteCond %{REQUEST_URI} -s [OR]
RewriteCond %{REQUEST_URI} -l [OR]
RewriteCond %{REQUEST_URI} -d
RewriteRule ^.*$ – [NC,L]

has to be changed to

RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} -s [OR]
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} -l [OR]
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} -d
RewriteRule ^.*$ – [NC,L]

Lesson 2:

In a VirtualHost container for ZF, there needs to be a DirectoryIndex index.php specifically there, at least for my case above of redirecting to /blog/. Otherwise the normal rules will decide to look for /blog/index.html and because that file doesn’t exist the rewrite rules will rewrite this to /index.php. If there is a DirectoryIndex statement, then /blog/ becomes /blog/index.php which does exist and is therefore exempted by the ZF rules.

Lesson 3:

The Alias directive (for example, and in particular for phpmyadmin) is only going to be applied on the resultant files system filename. For the incoming url /phpmyadmin apache must first go through its normal process of deciding where in the filesystem to find the script to be served. Once this is done, the alias is applied, if appropriate, to map any parts of the filesystem location that have /phpmyadmin to /usr/share/phpmyadmin. This means that the processing will go through all the rewrite rules and if the rewrite rules don’t make allowance for this somehow, the url will get mapped to index.php, the alias won’t apply,  and Zend will barf.

Lesson 4:

Though it is not specific to the ZF situation, I also learned that it is best to have a dummy VirtualHost that is never invoked as the very first VirtualHost declared. This is because the first declared VirtualHost becomes the “default”, and is the one that is used when the incoming url doesn’t actually match any of the VirtualHosts server names or server aliases.