Pound Best Practice Deployment

By Austin Godber

Pound is a load-balancing reverse HTTP proxy. It can also handle SSL connections. Pound, itself, does not serve content but just acts as a front end to servers that do. In this case pound will sit in front of a cluster of mongrel servers. This arrangement is similar to that illustrated on the Using Lighttpd with Mongrel page, except pound replaces lighttpd.

Requirements

We assume that the following:

  • Pound and the mongrel cluster are running on the same machine[1].
  • Pound 2.0.4 is built and installed, including SSL support if desired.
  • The mongrel gem is installed.
  • The mongrel_cluster gem is installed.

These instructions were performed on CentOS 4.3 using Ruby 1.8.4 from the CentOS 4 test repository. They should apply on other Linux distributions. They may work for other OSes, but please see the pound website for additional information.

Mongrel Cluster Setup

First we need to prepare our rails application to run in a mongrel cluster. In this example we will use mongrel_cluster to run three mongrel instances on ports 8000, 8001, and 8002. We then launch the mongrel cluster:

 $ cd railsapp/
 $ mongrel_rails cluster::configure -p 8000 -N 3
 $ mongrel_rails cluster::start

We should now have three instances of our rails app running on ports 8000, 8001, and 8002.

Configuring Pound

Now we configure pound to proxy requests to the rails cluster we just created. We will configure pound to accept both HTTP and HTTPS traffic on ports 80 and 443 respectively. Pound will then proxy requests to the Services listed in the configuration file. Our configuration file (/usr/local/etc/pound.cfg) looks like this:

ListenHTTP
  Address 0.0.0.0
  Port    80
  Service
    BackEnd
      Address 127.0.0.1
      Port    8000
    End
    BackEnd
      Address 127.0.0.1
      Port    8001
    End
    BackEnd
      Address 127.0.0.1
      Port    8002
    End
  End
End

ListenHTTPS
  Address 0.0.0.0
  Port    443
  Cert    "/usr/local/etc/test.pem"
  # pass along https hint
  AddHeader "X-Forwarded-Proto: https"
  HeadRemove "X-Forwarded-Proto"
  Service
    BackEnd
      Address 127.0.0.1
      Port    8000
    End
    BackEnd
      Address 127.0.0.1
      Port    8001
    End
    BackEnd
      Address 127.0.0.1
      Port    8002
    End
  End
End
</code>
</pre>

Before starting pound, we need to make sure our SSL certificate is present. If not we can quickly generate a test certificate:

 $ openssl req -x509 -newkey rsa:1024 -keyout test.pem \
   -out test.pem -days -nodes

It should now be safe to start pound:

 $ sudo pound -f /usr/local/etc/pound.cfg

Our Rails application should now be available at http://127.0.0.1/ and https://127.0.0.1/.

Testing SSL in Rails

The line AddHeader "X-Forwarded-Proto: https" in the ListenHTTPS section tells pound to add a header to the request as it is passed back to the mongrel servers[2]. This will tell the rails application that the request was originally an SSL request. We can test this with the following simple Rails controller, app/controller/test_controller.rb:

class TestController < ApplicationController
  def index
    @sslyn = request.ssl?
  end
end

And the accompanying view, app/views/test/index.rhtml:

<h1>test</h1>
SSL: < %= @sslyn %>

Visiting http://127.0.0.1/Test/ should show SSL: false while visiting https://127.0.0.1/Test/ should return SSL: true.

Building Pound on OSX

OSX has specific problems when building pound, but you can follow Trotter Cashion's to get everything working.


fn1. It is not required that pound run on the same machine as the mongrel servers. It was just chosen for this example.

fn2. Thanks to Joshua Harvey's post on the Mongrel mailing list for this fix.