Apache 1.3, Rails & lighttpd

March 27th, 2007

Apart from the WordPress blog, the dynamic parts of my Reinvented Software site is all Ruby on Rails. The pages there could be better (i.e. sexier), but I ran out of self-imposed time. I spent a few weeks last year rewriting those pages and what used to be an entire J2EE backend in Rails and felt cleansed as a result.

(Yes, I know J2EE was complete overkill - it would be for running the Universe - but when I set up the business, I wanted to keep my hand in just in case things didn’t work out and I’d end up back in corporate hell. Thankfully, that didn’t happen.)

My biggest concern was how to serve the files. My server is running Apache 1.3.x, I could have upgraded to Apache 2.0 but that would been a lot of work. I also heard Apache 2 working with FastCGI could be quite heavy on resources and that was off-putting. I could have moved entirely to lighttpd, but that was too scary, so I decided it would be better to serve the Rails stuff with lighttpd and have Apache do the rest.

I wrote about this on my personal blog at the time (boring my non-geek friends in the process). From the original post:

Apache proxies requests to Lighttpd to serve the Rails stuff (so, for example, you see http://reinventedsoftware.com/store/ instead of http://reinventedsoftware.com:3000/store/), it all works seamlessly.

While I could find instructions out there on how to get Apache proxy to Lighttpd to serve an entire Rails application from a specific URL (e.g. http://reinventedsoftware.com/myrailsapp/) this mixing and matching wasn’t documented - so I will probably put something about this on the Rails Wiki. It was quite straightforward once I had worked it all out.

Zach Hale came across the post and asked how to set up Apache to work alongside lighttpd, so here is how I did it. Note these instructions are for Apache 1.3.x, I don’t know how it would work with Apache 2:

Apache Setup

In Apache’s httpd.conf, ensure mod_proxy is loaded:

LoadModule proxy_module       libexec/libproxy.so

Then use the ProxyPass and ProxyPassReverse directives to lighttpd for certain paths (note the standard Rails stylesheets and javascripts directories also):

ProxyPass /news http://localhost:3000/news
ProxyPassReverse /news http://localhost:3000/news

ProxyPass /support http://localhost:3000/support
ProxyPassReverse /support http://localhost:3000/support

ProxyPass /stylesheets http://localhost:3000/stylesheets
ProxyPassReverse /stylesheets http://localhost:3000/stylesheets

ProxyPass /javascripts http://localhost:3000/javascripts
ProxyPassReverse /javascripts http://localhost:3000/javascripts

Lighttpd

In lighttpd.conf ensure server.modules includes mod_alias and mod_proxy:

server.modules           = ( "mod_rewrite", "mod_accesslog", "mod_fastcgi",
                             "mod_compress", "mod_expire", "mod_alias", "mod_proxy" )

And further down, add this to handle the aliasing:

$HTTP["url"] =~ "^/" {
  server.document-root = CWD + "/public/"
  alias.url = ( "/" => CWD + "/public/" )
  accesslog.filename = CWD + "/log/access.log"
  server.error-handler-404 = "dispatch.fcgi"
  server.errorlog          = CWD + "/log/lighttpd.error.log"
  server.indexfiles = ( "index.html" , "dispatch.fcgi" )
  # rails stuff
  fastcgi.server = ( ".fcgi" =>
    (
        (
       "socket" => CWD + "/log/code.socket",
       "min-procs" => 2,
       "max-procs" => 2,
       "bin-path" =>  CWD + "/public/dispatch.fcgi",
       "bin-environment" => ( "RAILS_ENV" => "production" )
  )))
}

I barely understand this stuff, so don’t ask me to explain it.

Finally, I created symlinks to all the root level folders in the Apache served public_html directory, so that lighttpd could find the files when the user navigates. Here’s a cut down ls -l:

dispatch.rb
dispatch.fcgi
dispatch.cgi
stylesheets
javascripts
support -> ../../../public_html/support/
news -> ../../../public_html/news
feeder -> ../../../public_html/feeder
kit -> ../../../public_html/kit
about -> ../../../public_html/about
blog -> ../../../public_html/blog
404.html
500.html

So, it’s a bit of a hybrid system. Apache is in control and serves most files, but lighttpd takes care of all the Rails stuff. It’s been running for 10 months now through some very heavy moments and works really well.