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]


_______________________________________________
Mongrel-users mailing list
Mongrel-users@rubyforge.org
http://rubyforge.org/mailman/listinfo/mongrel-users

Reply via email to