Monday, January 29, 2007

Multiple Ruby on Rails apps with Mongrel and Apache

This post will show how to deploy multiple Ruby on Rails applications using Apache2.2 and Mongrel Clusters. The goal is to serve many apps under the same domain, for example:

http://www.domain.com/app1
http://www.domain.com/app2


The topic was discussed on the Mongrel mailing list (http://rubyforge.org/pipermail/mongrel-users/2006-September/001498.html), but even after reading it over and over for a few days, I could not make any of the suggestions there work, hence this post of what I did to make it work.

Preparation: Get 1 Ruby on Rails app deployed first! For the instructions on getting a single Ruby on Rails app running using Apache2.2, Capistrano and Mongrel, check out these excellent tutorials. I use the configuration file layout suggested by the codahale blog.

http://mongrel.rubyforge.org/docs/apache.html
http://blog.codahale.com/2006/06/19/time-for-a-grown-up-server-rails-mongrel-apache-capistrano-and-you/

Once you have a single app deployed and working properly, it is relatively easy to get the second one running under your domain - if you know what to do. You will configure and deploy your second app exactly the same way you did the first, with one exception. For both apps, you need to change the mongrel configuration to use the --prefix argument, besides that it is only 2 changes to your apache configuration. Here are the steps in detail:

Step 1) Use the --prefix flag of the mongrel configuration, here are 2 example mongrel_cluster.yml files.

---
prefix: /app1
cwd: /var/www/rails/app1/current
port: "8000"
environment: production
address: 127.0.0.1
pid_file: log/mongrel.pid
servers: 2

----------------------------------------------------------------------------------
---
prefix: /app2
cwd: /var/www/rails/app2/current
port: "8010"
environment: production
address: 127.0.0.1
pid_file: log/mongrel.pid
servers: 2


Step 2) Modify your RewriteRules in ds.common to redirect to the appropriate app. Here is what I have in my ds.common for serving dynamic content.

# Redirect all non-static requests to the right cluster
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
RewriteRule ^/app1(.*)$ balancer://app1%{REQUEST_URI} [P,QSA,L]
RewriteRule ^/app2(.*)$ balancer://app2%{REQUEST_URI} [P,QSA,L]


Step 3) Add a new cluster to proxy_cluster.com.
<Proxy balancer://app1 >
BalancerMember http://127.0.0.1:8000
BalancerMember http://127.0.0.1:8001
</Proxy >

<Proxy balancer://app2 >
BalancerMember http://127.0.0.1:8010
BalancerMember http://127.0.0.1:8011
</Proxy >

9 comments:

Unknown said...

That's a cool post, thanks for the info!

askegg said...

Nice - I will try this out tonight. Do you know if there is anyway to get a mongrel cluster to respond to different domains, eg:

http://www.myapp1.com/
http://www.myapp2.com/

Pierre Rigal said...

Nice post.

Askegg> You can use a classic VirtualHost setup with the ServerAlias directive.

<VirtualHost *>
ServerName www.myapp1.com
ServerAlias www.myapp2.com
...
#Proxy Directives
</VirtualHost>

Then you just have to redirect all / to your balancer. You can have a look to my setup for more details.

Tom Chappell said...

When I try this, it *almost* works, but it attempts to serve up images from, for example:
  .../myapp1/myapp1/images/...
instead of from
  .../myapp1/images/...
so it doesn't find the images.

Tom Chappell said...

Ha, it's all working now. The ill-written project that I was trying to deploy was running image URL's through the image tagging helper methods zero times, on some pages, and was sending them through the image taggers twice on some other pages. Sort of goes without saying: once is the preferred number, and no pages were doing that, geez.

In the standard root-level deployment, this didn't matter, but when you're /prefix-hosted, you've got to be careful. All better now.

James said...

Wow; you rock my world!

I worked on this for hours, before finding your post.

Bart said...

Hi,

I've followed the instruction to get a 2nd app running but I'm having a problem deploying it:

The original still runs from the domain, but the 2nd won't start up from domain/vm. I don't see the mongrel clusters when listing processes (pid's) either

My error when deploying is:

** [out :: localhost] Couldn't find any pid file in '/home/user/live/app2/current/tmp/pids' matching 'dispatch.[0-9]*.pid'
** [out :: localhost] (also looked for processes matching "/home/user/live/app2/current/public/dispatch.fcgi")

Any suggestions?
Thanks

Waheed Barghouthi said...

wow how simple is it... i salute you for clarifying the prefix method in your post thanks...

Unknown said...

Hi
Thanks for the post. I have some follow up questions. Do you have an email?