[Mongrel] Sharing a mongrel cluster in a multi-url environment

John Almberg jalmberg at identry.com
Wed Jan 28 08:52:50 EST 2009


I have a 2.2.2 ROR website package that I sell to my clients. After  
deploying a few instances, I realized that the only difference  
between the accounts was the client's URL and the database. It seemed  
wasteful to have many copies of the same software on my web server,  
not to mention a separate mongrel cluster for each client, most of  
which were running at very low load levels.

So I had the idea of combining all these separate websites into one  
'shared' system. Having no idea how to do that, I had to wing it.  
Here's what I'm using:

1. Apache as the front end server, running mod_proxy
2. A single mongrel cluster (4 mongrels)
3. A single instance of my Rails application

I had each Apache virtual host configuration insert a unique  
client_id header in all requests, like so:

	RequestHeader set X_CLIENT_ID '7563TY7732UUW9'	# a unique id for  
each domain

The Rails app then reads this header and knows which client database  
to use.

Thus, a request comes in for the url example1.com, Apache adds the  
unique X_CLIENT_ID header for that URL, the request gets forwarded  
through Mongrel, Rails reads the client_id, connects to the correct  
database, and then renders the page as it would if this were not a  
multi-domain system.

This all works very well except for one serious problem: mongrel  
seems to mess up cookie handling in a multi-domain situation.

The problem is illustrated in the log snippet at the bottom of this  
email:

The 1st request is from User 1, already logged in and working on  
example1.com.

The 2nd request is from User 2, for the example2.com home page.

The 3rd request is from User 1, for another page in the application.  
The HTTP request included the original cookie, but note that the  
cookie value, the session id that Rails sees, has changed!

The 4th request shows User 1 being redirected to the login page,  
because to Rails it looks like User 1 is a new, un-authenticated  
user, who does not have the rights to access that page.

If no one ever accesses example2.com, then the users of example1.com  
have no problem. That is, their cookies are not changed. However, as  
soon as anyone hits example2.com, anyone subsequently hitting  
example1.com will have their session_id cookie changed. The same is  
true in the other direction... hits on example1 also change the  
cookies of users on example2.

I can solve the problem by not sharing mongrels. That is, by keeping  
everything else the same, but dedicating one or more mongrel  
instances to each URL. As soon as mongrel stops handling multiple  
URLs, the cookie problem vanishes.

However, this gets me back to having one or more mongrels for each  
domain, which seems wasteful. A single mongrel cluster of 4 or 6 can  
easily handle the load, if it weren't for this cookie problem.

Can anyone explain this problem to me? I don't actually understand  
why mongrel doesn't just pass the cookie in the request straight  
through to Rails. Why does it change it?

And can anyone suggest a work-around?

Or perhaps I've got the wrong end of the stick, and it's not  
Mongrel's fault? Or maybe I should take an entirely different  
approach to this multi-domain problem? As I said, this is straight  
out of my head. I have not been able to google any other approach to  
what I'm trying to do here.

Any help, much appreciated. Again, this is a fully upgraded Rails  
2.2.2 system.

-- John


     **1st Request from USER 1 for example1.com**
         Processing Admin::CmsController#index (for 75.127.142.66 at  
2009-01-27 13:15:27) [GET]
           Session ID: 00b9cfb6fd397e5c9934ea58eaef648d
         >>> Request for client 90873721, EXAMPLE1.COM
         Rendering template within layouts/admin/standard
         Rendering admin/cms/list
         Completed in 114ms (View: 14, DB: 81) | 200 OK [https:// 
example1.com/admin/cms]

     **2nd Request from User 2 for example2.com**
         Processing CmsController#cms_show (for 64.1.215.163 at  
2009-01-27 13:16:15) [GET]
           Session ID: 4fed1c59001f7484a63fb6280376825a
           Parameters: {"alias"=>"home.html"}
         >>> Request for client 48218343, EXAMPLE2.COM
         ### alias: home.html
         Rendering template within layouts/two-column
         Rendering cms/cms_show
         Completed in 23ms (View: 13, DB: 3) | 200 OK [http:// 
example2.com/]

     **3rd Request from User 1 for example1.com -- note session ID  
changes!!!**
         Processing Admin::CmsController#index (for 75.127.142.66 at  
2009-01-27 13:16:18) [GET]
           Session ID: 85c178aa70ed2bef6a767e844bf6c6d6
         >>> Request for client 90873721, EXAMPLE1.COM
         ####### 'admin/cms', 'index'
         Redirected to actionsignincontroller/admin/user
         Filter chain halted as [:check_authentication]  
rendered_or_redirected.
         Completed in 4ms | 302 Found [https://example1.com/admin/cms]

     **4th request -- redirected from 3rd request**
         Processing Admin::UserController#signin (for 75.127.142.66  
at 2009-01-27 13:16:18) [GET]
           Session ID: 85c178aa70ed2bef6a767e844bf6c6d6
         >>> Request for client 90873721, EXAMPLE1.COM
         Rendering template within layouts/admin/standard
         Rendering admin/user/signin
         Completed in 10ms (View: 6, DB: 0) | 200 OK [https:// 
example1.com/admin/user/signin]




More information about the Mongrel-users mailing list