iosart.com | projects | articles | photos | about

Fooling Apache

Tweaking with the Apache configuration, I encountered some pretty interesting problems.

I used mod_rewrite to serve different content based on the HTTP request. Basically, what I was trying to do is this: there are two domains, “one.com” and “two.com” both pointing to the same server. If the user used the first domain name in the address, serve “Page A”, else serve “Page B”. This can be accomplished quite easily by using the RewriteCond %{HTTP_HOST} ^one.com$ directive.

I used the above technique and all was well, until I noticed that the images served by the one.com domain are not being cached by the browser! To find out what was going on I used wget with the “-S” option to see the full header returned by the server. The server was returning a header which included a “Vary: Host” field, which means that the server didn’t serve a regular static page, but its reply depends on the “Host” field in the HTTP request. Browsers interpret this as “the content returned is dynamic, don’t cache it.

I needed to get rid of the “Vary” header. One option was to use the Header unset Vary directive, but that requires mod_header module, which is unfortunately isn’t included in my server. Another option is to use the SetEnv force-no-vary directive. This tells the server not to return the “Vary” field.

It seams like problem solved… Not exactly. SetEnv force-no-vary along with suppressing the “Vary” header, forces the response to be HTTP/1.0. Why is this a problem? When serving HTTP/1.0, some advanced features of HTTP/1.1 aren’t used. One of these features is “Keep-Alive”. This feature can increase the loading time of the page by up to 50% by using the same connection for more than one request. Turn this off and it takes much longer to load pages with many images – and this incidentally was exactly the type of pages I was serving!

So “SetEnv force-no-vary” is out too. What can be done to make the server stop sending the damn “Vary” header? I needed a way to fool the server so it doesn’t notice I’m checking the Host header field. A simple solution then came too mind – what if I save the HTTP_HOST value in an environment variable and use this variable in the condition directive. The server won’t have any way of knowing that this variable actually contains the HTTP_HOST and stop sending the “Vary” field. I used the following code:


RewriteRule .*  - [E=MY_HTTP_HOST:%{HTTP_HOST}]
RewriteCond %{ENV:MY_HTTP_HOST} ^one.com$

The first line sets a new environment variable “MY_HTTP_HOST” and initializes it with HTTP_HOST. The second line is the condition and it looks to the server as if I check a regular environment variable. This finally solved the problem.

5 Responses to “Fooling Apache”

  1. Larry Matter Says:

    Thanks for taking the time to put this info up. I had the exact same problem and you saved me a lot of grief.

  2. Christian Says:

    Great idea!

    Another solution is to use SERVER_NAME instead of HTTP_HOST. This only works if UseCanonicalName is Off, though.

  3. Tobias Says:

    This ”problem’ of serving different content from off one server seems to be very common. I or myself tried the solution buildin into Apache through the ‘Virtual Host’ approach.
    Name-based VHosts do exactly what you are tring to archieve: serving content based upon the requested domain/hostname. This even ives the ability to create ‘failback hosts’ so, if the server is requesed either of its ‘dns’ or vhost-names or its ip-address , the server responds the respoective content (from the vhost) or if no matchin vhost is found, it serves the default one.

  4. Iosart Says:

    Tobias,
    The problem I was trying to solve was achieving functionality similar to “Virtual Hosts” without being able to add new Virtual Hosts to Apache config files. If you have full control of the server there are of course easier ways.

  5. Daves Says:

    Your tip to create MY_HOST does not work for me, but SERVER_NAME mentioned in comments does it well… thanks.