Hunchentoot behind a proxy server

Having a lightweight http server (in this case Nginx) proxy request to Hunchentoot offers some advantages over letting Hunchentoot speak directly to the web:

  1. You can have nginx serve all the static files for you app, this way serving them faster while freeing lisp process for generating only dinamic content.
  2. You can take advantage of nginx caching strategies.
  3. You can use nginx for load-balancing.

Step 1 – Installing and running nginx

Let’s get to work then, first we must start by installing nginx, this is easy using apt-get.

$ sudo apt-get install nginx

After nginx is installed you can start/stop/restart the server with the commands:

$ sudo /etc/init.d/nginx start
$ sudo /etc/init.d/nginx stop
$ sudo /etc/init.d/nginx restart

As you can see there’s nothing special about it. After starting the server if you browse to that machine’s ip address/domain name.

http://67.19.123.145

You should now see nginx default web page.

Step 2 – Configuring nginx

The global server settings are stored in /etc/nginx/nginx.conf, this file holds the options to control overall nginx behaviors, things like maximum worker connections, enabling/disabling gzip, defining connection timeouts and so on, for now let’s keep the default configuration.

When dealing with virtual hosts, the preferred way of doing this is, similar to apache 2, to have a configuration file for each virtual host inside /etc/nginx/sites-available, you can easily enable/disable these virtual hosts by creating/removing symlinks to these files on /etc/nginx/sites-enabled, all files in this last directory are loaded by default by nginx.conf.

Step 3 – Setting up proxied requests to hunchentoot

First i’ll remove the default entry from /etc/nginx/sites-enabled, i will simply remove the symlink, this way if i later need it i still have the default configuration file in /etc/nginx/sites-available.

$ sudo rm /etc/nginx/sites-enabled/default

Now i’ll create a file for my virtual host with the desired configuration.

$ sudo emacs /etc/nginx/sites-available/sample.ponto-dot.com

Before i even configure the virtual host i’ll enable right away.

$ sudo ln -si /etc/nginx/sites-available/sample.ponto-dot.com /etc/nginx/sites-enabled/sample.ponto-dot.com

Now for the configuration of my virtual host, here’s my configuration file:

Step 4 – Understanding the configuration file

In this block we define a server cluster, if you have multiple hunchentoot instances running somewhere you can add multiple entries. When the request arrives if the first instance is busy the request tries the second instance and so on until it finds an instance free or errors out. If you were to setup load-balancing this would be the place where you would configure it.

The server block is where the virtual host is defined. In this example we set the server (virtual host) to listen on port 80 and define the server_name (the domain name of this virtual host). Next we define the document root, which means that all the requests will be mapped to files inside that directory, so for instance:

http://sample.ponto-dot.com/test.html

Will resolve to the file

/var/www/sample.ponto-dot.com/public/test.html

Now we get to the critical section where we will process our request and if desired control how to respond to the incoming request.

The location directive will execute everything inside the block if the request matches the provided expression, in our case “/” will match every request containing “/” meaning it will match every request. You can have multiple location blocks inside your server block.

Checks if the request is for a directory and if it contains the file index.html inside, if it exists it will rewrite the request url to include index.html and breaks out of rule processing to serve that file.

http://sample.ponto-dot.com/images/

Will check for the existance of:

/var/www/sample.ponto-dot.com/images/index.html

and serve that file if it exists.

We start by setting the values of two HTTP Headers, X-Real-IP and Host, to be used if the request is proxied. I do this because otherwise they won’t be passed onto our hunchentoot server and i will need those in my application.

Then we check if the request resolves into an existing file. If it doesn’t, we assume it must be handled dynamically and thus send the request to be processed by Hunchentoot.

Step 5 – Testing it out

We’ll need to restart nginx to test it out.

$ sudo /etc/init.d/nginx restart

However, if you test this right now you will always end up in the hunchentoot web page because there are no files inside your document root, let’s create two files for testing it in action.

Now if i browse to http://sample.ponto-dot.com i get

browsing to http://sample.ponto-dot.com/foo/ gives me

while browsing to any kind of urls like http://sample.ponto-dot.com/anything or http://sample.ponto-dot.com/foo/test.asp will show me
Hunchentoot Default Page
Final thoughts

Obviously this is a really basic setup but a working one and that’s what i was really interested, getting it to work. One should really check the nginx wiki for detailed documentation on all of the directives available. One thing i’m also interested in trying is full load-balancing and memcached setup but i’ll leave that for a time when i know what i’m doing.

2 thoughts on “Hunchentoot behind a proxy server”

  1. Thanx for great articles on hunchentoot and nginx they helped me a lot.

    I just have one suggestion and that is to expand the example to a virtual host example. Getting one hunchentoot to serve multiple domains behind nginx was the really hard part to figure out on my own.

  2. Thanks for your comment Phil.

    I have very few real web applications in Common Lisp and all those being for different customers ended up running in different hosting setups and thus my lack of experience with what you suggest. Nevertheless i’ll keep your suggestion in mind and will work through that kind of setup should i ever work on one.

Leave a Reply to jadawin Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.