S.E.A.N.I.C.U.S.

Monday, February 27, 2006

Riding the Rails

At work I've been learning how to write web applications using Ruby on Rails. It's pretty awesome framework, but deployment can be a pain in the butt. Here's some tips for deployment.
  • If possible, avoid Apache at all costs--there are just too many compatibility issues between FastCGI and Apache. Use lighttpd instead.
  • If you have to use Apache (as in our case), set it up to do reverse proxying to your own locally-bound lighttpd server. This way you can keep your existing Apache, and add on lighttpd instances as need be.
  • There's a lot of discussion out there on how to set up lighttpd to use virtual hosts, which is pretty easy. But this doesn't help much if:
    1. You want to use the reverse proxy setup I mentioned.
    2. You want multiple Rails apps on a single domain.
    Here's what you can do instead, and I don't take all the credit for this, others have done most of it... (to be placed in your lighttpd.conf file, or in a separate file as I demonstrate later):
    $HTTP["url"] =~ "^/myapp" {
    server.document-root = "/path/to/myapp/public/"
    alias.url = ( "/myapp/" => "/path/to/myapp/public/" )
    server.error-handler-404 = "/myapp/dispatch.fcgi"
    server.indexfiles = ( "dispatch.fcgi", "index.html" )
    fastcgi.server = ( ".fcgi" =>
    (( "socket" => "/tmp/myapp.socket1",
    "bin-path" => "/path/to/myapp/public/dispatch.fcgi",
    "min-procs" => 1,
    "max-procs" => 1,
    "bin-environment" => ( "RAILS_ENV" => "production" )
    )))
    }

  • To be able to make configuration of my Rails apps as independent as possible, I created a conf.d directory that contained two subdirectories, apache and lighttpd. In each of these subdirectories, I created .conf files for each application. The Apache files contain the information on how to perform the reverse proxy, the lighttpd files contain snippets as shown above. The Apache files look like this:
     <IfModule mod_proxy.c>
    ProxyRequests Off
    ProxyPass /myapp/ http://localhost:81/myapp/
    ProxyPassReverse /myapp/ http://localhost:81/myapp/
    <Proxy *>
    Order deny,allow
    Allow from all
    </Proxy>
    </IfModule>
    So then all these configuration files are hooked into the current webserver configurations with two other files and a single line.

    First, I created a rails.conf file Apache's conf.d directory. In the file, I put this line:
    Include /path/to/rails/conf.d/apache/*.conf
    This includes all of the .conf files in the apache directory we created earlier, so they get processed when Apache starts up.

    Since lighttpd doesn't have a built-in feature like that, I wrote this shell script (addconf.sh):
    #!/bin/sh
    # dump all of the config files to stdout so it can be read by lighttpd
    if [ -f /path/to/rails/conf.d/lighttpd/*.conf ]; then
    for i in `ls /path/to/rails/conf.d/lighttpd/*.conf`
    do
    cat $i
    done
    fi
    exit 0
    You can then use the include_shell "/path/to/addconf.sh" command in your lighttpd config file.


Best of luck to you and your Rails projects, and please share your comments about the code.