Using Apache's Proxy and Virtual Hosts with Maque
Maque's HTTP Server is a powerful tool for development and testing, but it is not designed to be a replacement for production-level HTTP servers or web application servers such as Apache, Nginx, Mongrel, Jetty, etc. In this article we will examine how to integrate Maque into an Apache based development environment by using Apache's proxy and virtual hosts features.
Common Development Environments
There are two common development/server stacks that web-developers use on a day-to-day basis. The first is a static-site based configuration. This configuration has an HTTP server that simply acts as a file server, looking up incoming requests and then returning the static content.
Maque's HTTP server is perfect for this kind of scenario. You can use the htdocs folder to store the assets and then serve back the files as the requests come in. Although this is a classic HTTP server configuration, very few sites today use this kind of static content configuration.
A more prevalent configuration is an HTTP front-end that handles static requests and then a web-server that has certain requests proxied (forwarded) to it via the HTTP server to handle dynamic generation of content. This is how PHP, Ruby on Rails, Python, Java, Lift and many other web-application configurations work.
Because Maque is not designed to be a production-level server nor does it handle proxying, how can we integrate it into our application development workflow? One approach is to host our project via the development stack of our choice such as Apache -> Mongrel -> Rails and then only host the services we want to simulate via Maque.
Let's examine a possible scenario to show how this would work. First, our configuration uses MAMP (Mac, Apache, PHP & MySQL stack) locally to host our application. By default, MAMP runs on port 8888, so when we host our site locally we navigate to http://localhost:8888/ to test and develop our application. Now, the services we want to simulate are an API that we need to asynchronously load using Ajax. These API services are not live yet, or not available to us locally, but the pathing to the services will be relative to the root URL, such as ./api/employee/search.
So, back to the original issue, how do we simulate that API with Maque? Maque's HTTP server (and rule processor) runs by default on port 5656. Since we are already running Apache on 8888 you can not have any other service running on the same port, this means we can't try and overlay Maque and Apache on port 8888. The first thing we could try is to change all our service calls from ./api/employee/search to http://localhost:5656/api/employee/search and then we could build all our rules to simulate our API. Once we test our code we could then go back and update all the URLs back to the real pathing.
This approach is hardly ideal. First, we have to modify our code before launch and hope we don't miss any old references to the Maque API address. The second issue, and this one is a huge one, is that having the browser call from port 8888 to port 5656 is considered a cross-domain call and is blocked by browser-based clients. There are some ways around it, such as using iFrames and other configurations but there is an easier and more code-safe approach.
Apache has two modules called mod_proxy.so and mod_proxy_http.so. These modules' responsibility is to forward requests to a different location by making it look like the returning data is coming from the original path. This is how most of the web application configurations work, the incoming HTTP request is proxied to Mongrel (or Jetty, Tomcat, etc), and then Mongrel responds. These web-servers run on different ports than the HTTP server, so if we just forwarded the request we would get the same cross-domain issue. By hiding these forwards behind a proxy, we make it look like our original request is being responded to by the HTTP server.
We can take advantage of this with Maque. Apache is configured via the httpd.conf file. Within this file we can enable the proxy mods (they are usually already on so double-check for their existence)
LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_http_module modules/mod_proxy_http.so
Then we can define what gets proxied. Using our example, we want all requests going to /api/... to be forwarded to Maque. We do this by defining the ProxyPass and ProxyPassReverse at the bottom of the http.conf file:
ProxyPass /api http://localhost:5656/api ProxyPassReverse /api http://localhost:5656/api
When we add these commands we are telling Apache that whenever a request comes in that starts with http://localhost:8888/api forward this to http://localhost:5656/api and respond back to the requester with whatever the redirected server sends back. So now our configuration looks more like this:
Apache can now systematically determine who is responsible for responding to a specific request. This also allows us to continue to use relative paths in our application and not worry about cross-domain or cross-scripting issues because as far as the client can tell, its all coming from the same location and server.
Apache Virtual Hosts
The last thing we want to look at is handling multiple application environments from a single server. If we simply add the ProxyPass at the bottom of the httpd.conf file this means that all requests to /api get forwarded. This is fine if we are only working on one site, but what happens if you have multiple sites?
A common solution for this is setting up Virtual Hosts for Apache. Virtual Hosts allow you to set up configurations and "name" your servers and their location. For example, at DevelopmentArc we have multiple client configurations as well as our own sites. Instead of using http://localhost to navigate to a project we configure our machines to follow this pattern: http://dev.local.[project]/. So we have http://dev.local.maqueapp/ pointing to Maque's local development site and http://dev.local.developmentarc/ pointing to our company's local development site.
The first thing we need to do is update the hosts file. The hosts file defines what host names get mapped to what location.
- OS X: /etc/hosts
- Windows: C:\windows\system32\drivers\etc\hosts
Before you start editing the hosts file, please make a backup. We also highly recommend that you read up on how the hosts file works so that if you accidentally misconfigure it, you can get back to a stable state.
In the hosts file you will see a line that looks like:
You can append on the new server names to this line by giving it spaces or you can add more lines at the bottom that follow the same "IP Name" structure:
127.0.0.1 localhost dev.local.maqueapp dev.local.developmentarc
Once you have added the new names, you can save the file. Next, we need to add the virtual hosts to the Apache httpd.conf file. Virtual hosts are defined at the bottom of the file, and they will replace the ProxyPass/ProxyPassRevers lines you may have previously added. The Structure looks like this:
<VirtualHost dev.local.maqueapp> DocumentRoot "~/Documents/htdocs/maqueapp" ServerAlias dev.local.maqueapp ServerName dev.local.maqueapp ProxyRequests Off ProxyPass /api http://localhost:5656/api ProxyPassReverse /api http://localhost:5656/api </VirtualHost>
As you can see, we give a name to the Virtual hosts, that matches our configuration in the hosts file. We also define a document root, this is where our HTML and other files live and then we define the proxy. This enables us to create different proxy paths for different project or server paths. Once you restart Apache, the new configuration should be loaded and navigating to http://dev.local.maqueapp:8888/ will take your application.
Hopefully, this article shows you how to leverage Apache's ability to proxy requests to integrate Maque into your development environment. Using this ability can allow you to easily simulate your services without having to change code or deal with cross-domain issues in your application.