Saturday, April 25, 2009

Apache + JRuby + Rails + GlassFish = Easy Deployment!

It occurred to me today that a lot of people probably want a JRuby deployment option that works with a front-end web server. I present for you the trivial steps required to host a JRuby server behind Apache.

Update: It's worth mentioning that this works fine with JRuby + Mongrel too, though Mongrel doesn't automatically multithread without this patch and Rails' production.rb config.threadsafe! line uncommented. The GlassFish gem will automatically multithread with several JRuby instances (in the same server process) by default or a single JRuby instance with config.threadsafe! uncommented.

Prerequisites:
  1. Apache with mod_proxy_http enabled (sudo a2enmod proxy_http on Ubuntu)
  2. Java (sudo apt-get install sun-java6-jdk or the openjdk flavors if you like)
  3. JRuby (download, unpack, put bin/ in PATH)
  4. gems appropriate to run your app with JRuby (e.g. rails, activerecord-jdbcsqlite3-adapter, etc)
  5. production DB all set to go
Ok. I'm no Apache expert, so I'm sure there's some tweaking necessary for this. Please add your tweaks and suggestions in comments. But basically, all you need to do is run your app using the GlassFish gem and set up Apache to proxy to it. It's that simple.
  1. Install the glassfish gem
    gem install glassfish
  2. From your application directory, run glassfish with these options:
    glassfish -p <port> -e production -c <context> -d
  3. Add ProxyPass and ProxyPassReverse lines to Apache (whereever is appropriate on your system) for the GlassFish server instance. For example, if <port> is 9000 and <context> is foo:
    ProxyPass /foo http://localhost:9000/foo
    ProxyPassReverse /foo http://localhost:9000/foo
  4. Reload Apache config, however is appropriate for your system
You'll now be able to access your app via http://servername/foo, and requests will all proxy to the GlassFish server instance.

This doesn't do anything to manage the server instance, but since GlassFish can start up as a daemon now, it should be easy to wire into whatever you normally use for that.

A few caveats:
  • I had some trouble getting mod_proxy to allow requests to proxy through. There's probably a right way I'm not doing, so I won't say what I did. If you know the ideal mod_proxy config for this sort of thing, post it in comments
  • Although the GlassFish gem is really nice already, we're still working minor kinks out of it and it may still have minor bugs. If you run into something, let us know and we'll get it fixed (and of course, you can use this mod_proxy setup with Mongrel too, if you like).
  • I'd love to get some help putting together something that manages servers similar to Phusion Passenger, because that's really the only missing piece here.
I'll update this post as suggestions come in. Enjoy!

Update: Dberg suggests the following improvement:
the one thing you want to remember to do also is to exclude the static assets that normally get served out of rails. To do this simply add some proxypass exclude lines like

ProxyPass /images !
ProxyPass /javascripts !
ProxyPass /stylesheets

Then make sure DocumentRoot is set to the right place for these files and you will get a slight performance boost !
Thanks for that!

4 comments:

  1. Awesome :-) we use jboss instead of glassfish. And we use Mod Security too, we have 2 apache in production, the first with mod security, then mod_proxy and then jboss.

    ReplyDelete
  2. the one thing you want to remember to do also is to exclude the static assets that normally get served out of rails. To do this simply add some proxypass exclude lines like

    ProxyPass /images !
    ProxyPass /javascripts !
    ProxyPass /stylesheets

    Then make sure DocumentRoot is set to the right place for these files and you will get a slight performance boost !

    ReplyDelete
  3. Dberg: That's a very god point, since Apache will certainly be faster at serving these resources than Rails. Thanks!

    ReplyDelete
  4. Actually, I don't think Glassfish will be much slower than Apache at serving statics.. Of course there is the proxy-passthrough performance hit.

    ReplyDelete