7. Running Agavi Behind a Reverse Proxy

If you are developping an Agavi application that needs to run behind a Reverse Proxy , you need to be aware of a few things. The main issue is that there is a difference between the public DNS for you applciation and the internal, unregistered DNS. A reverse proxy intercepts all calls for the public IP address and decides what to do with them. It will decide what internal webserver to forward to (there can be several webservers running the same application to help balance the load). As a result your application receives a call from the Reverse Proxy and not from the client.

This means that some of the $_SERVER[] variables just contain the info for the reverse proxy and not for the client (e.g. $_SERVER[REMOTE_ADDR] will be the IP address for the reverse proxy). This is one of the reasons why it's a bad idea to rely on the client's IP address for security. You'll also notice that variables like $_SERVER['SERVER_NAME'] contain info about the server within the network, but this address is unknown to the outside world. E.g A client makes a request for http://www.foo.com. A Reverse Proxy intercepts this and forwards this request to an internal server http://internal1.foo.com. In this case the SERVER_NAME variable will be set to 'internal1.foo.com' and not to 'www.foo.com'.

Now if you're using Agavi you should seldom have to deal with the contents of $_SERVER[]. But sometimes you have to generate an absolute url (e.g. as a link in a rss feed or a <base href="..." /> tag in html). You can do this by calling the gen() method on Agavi's Routing class with the optional parameter 'relative' set to false

<link><?php echo $ro->gen( 'Newsitem' , array( 'id' => 5 ) , array ( 'relative' => false ) ); ?></link>

In a setup with a Reverse Proxy this would generate an url like http://internal1.foo.com/news/1. This is not what we want. Since internal1 is not known to a public dns server any user that follows the link will receive a host not found error.

One way to deal with this is to let the Reverse Proxy rewrite all html it sends back to the client. Information for this kind of setup can be found in the manual for the Reverse Proxy. E.g. for Apache 2 see http://www.apachetutor.org/admin/reverseproxies . Another option is to use some of the alternate variables that are set by Apache (I have no idea how other webservers handle this). You can view these by looking at the output of the phpinfo() function. With php 5.1.6 under Apache2 I have access to HTTP_X_FORWARDED_FOR, HTTP_X_FORWARDED_HOST and HTTP_X_FORWARDED_SERVER.

Armed with this information we can tell Agavi where to get the name of the server. This information is needed by the AgaviWebRequest object. To do this we need to edit factories.xml.

<request class="AgaviWebRequest">
  <parameters>
    <parameter name="sources">
      <parameter name="SERVER_NAME">HTTP_X_FORWARDED_SERVER</parameter>
    </parameter>
  </parameters>
</request>

This tells Agavi to use the value of HTTP_X_FORWARDED_SERVER for SERVER_NAME, ensuring that absolute urls are correct.