Ruby on Rails
HowtoDeployMoreThanOneRailsAppOnOneMachine

There are several ways to host multiple rails apps on one server; if they are small and there is no conflict between their name spaces you might consider merging them into one “super app”—but for anything larger than toy apps, this is simply asking for trouble,

Deployment in separate folders for each app on one Apache server

WikiGardening required. This section may be out of date, make sure you read the surrounding sections too.

Suppose you’d rather have various Rails apps running on your machine in different folders, with URLs like:

<a href="http://www.myhost.org/appOne/">http://www.myhost.org/appOne/</a>...
<a href="http://www.myhost.org/appTwo/">http://www.myhost.org/appTwo/</a>...

This is very easy if you are using Apache & mod_rewrite.

  1. Put a symlink to each application’s directory in your document root (e.g., “ln -s /opt/rails/appOne /var/www/html/appOne” and so forth for each application)
  2. In each application’s .../appName/public/.htaccess file, add the line “RewriteBase /appName” right after the “RewriteEngine On” line.
  3. In your main httpd.conf file do something like this:
    <VirtualHost *>
        ServerName <a href="http://www.myhost.org">www.myhost.org</a>
        DocumentRoot /var/www/html/
        RewriteEngine On
    
        RewriteCond %{REQUEST_URI} !^/appOne/public
        RewriteRule ^/appOne(/.*)?$   /appOne/public$1
        <Directory /var/www/html/appOne/public/>
            Options ExecCGI FollowSymLinks
            AllowOverride all
            Allow from all
            Order allow,deny
        </Directory>
    
        RewriteCond %{REQUEST_URI} !^/appTwo/public
        RewriteRule ^/appTwo(/.*)?$   /appTwo/public$1 
        <Directory /var/www/html/appTwo/public/>
            Options ExecCGI FollowSymLinks
            AllowOverride all
            Allow from all
            Order allow,deny
        </Directory>
    
    </VirtualHost>
    
    
Note that this differs from the normal in three regards:

As requests come in, they are rewriiten based on the appName and then handled normally.

Even Simpler Method

  1. Follow the first step from above (i.e. create symlinks to the public folders of each of the rail applications)
  2. Then in the main httpd.conf, do this:
    <VirtualHost *:80>
        ServerName localhost
        DocumentRoot /Users/bob/Sites/
        RewriteEngine On
    
        <Directory /Users/bob/Sites/>
            Options FollowSymLinks
            AllowOverride all
            Allow from all
            Order allow,deny
        </Directory>
    
    </VirtualHost>
    

This is using Rails version 0.12.1, Apache 2.0, and OSX 10.4

Multiple Rails Apps On Windows with Apache 2.0 and Rails 0.13

Similar to the other instructions, but with some minor changes. Symbolic links don’t work well on Windows servers unless you use Junctions, but it turns out that it’s not needed.

  1. Make a folder for your web pages
    c:\web\apps
  2. Place each rails directory under this folder
       c:\web\apps\
       c:\web\apps\blog
       c:\web\apps\blog\public
       ....
      c:\web\apps\todolist\
      c:\web\apps\todolist\public
      .....
    
  3. Place this at the end of your Apache configuration
    Alias /blog "c:/web/apps/blog/public" 
    # uncomment next line if you have enabled fastcgi
    #FastCgiServer c:/web/apps/blog/public/dispatch.fcgi -idle-timeout 120  -initial-env RAILS_ENV=production -processes 1
    <Directory c:/web/apps/blog/public>
      Options ExecCGI FollowSymlinks
      AllowOverride All
    </Directory>
    
    Alias /todo "c:/web/apps/todo/public" 
    # uncomment next line if you have enabled fastcgi
    #FastCgiServer c:/web/apps/todo/public/dispatch.fcgi -idle-timeout 120  -initial-env RAILS_ENV=production -processes 1
    <Directory c:/web/apps/todo/public>
      Options ExecCGI FollowSymlinks
      AllowOverride All
    </Directory>
    
    
  4. Next, you’ll have to edit the .htaccess file in each Rails app. You’re going to need to change the dispatch.cgi to dispatch.fcgi (if you’re using fast-cgi) but more importantly, you’re going to need to add
       RewriteBase /blog
     

    to your /blog app and then do the same for the /todo app
  5. Do the same fo the other application, making sure to specify the paths appropriately.
  6. NOTE: If you want the blog app to reside at /blog and the todo app to reside at /, use the following RewriteCond and RewriteRule in httpd.conf (in addition to RewriteBase in .htaccess):
    <VirtualHost *:80>
        ServerName mybox.company.com
        DocumentRoot c:/web/apps/
        RewriteEngine On
    
        RewriteCond %{REQUEST_URI} !^/todo/public
        RewriteCond %{REQUEST_URI} !^/blog
        RewriteRule ^(.*)?$ /todo/public$1
    
        <Directory c:/web/apps/todo/public>
        ...
        </Directory>
    
        RewriteCond %{REQUEST_URI} !^/blog/public
        RewriteRule ^/blog(/.*)?$ /blog/public$1
    
        <Directory c:/web/apps/blog/public>
        ...
        </Directory>
    </VirtualHost>
    
  7. Be sure to update your environment files if you are using this for production! Also be sure to make sure you know HowtoChangeSessionOptions because you could end up with session errors if you’re not careful.
    Add this to the end of your config/environment.rb file
    ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS.update(:prefix => 'blog.')
    

    and do the same for the todolist application.
  8. At that point, everything should work as expected. You should be able to do http://mybox.company.com/blog/ and pull up the blog application to ensure that you don’t have problems loading sessions.
  9. Make sure that you have the very latest dispatch.fcgi file and the latest .htaccess file. Don’t waste hours trying to make this work like I did only to find out you have the wrong files.

Han Holl rails.conf

# Directory based Rails apache configuration without per directory mod_rewrite
# Two global replaces (in the right order) should suffice to relocate
# This file can be dropped in /etc/httpd/conf.d as rails.conf -- no need to touch httpd.conf
# Can co-exist with other parts of a website and other rails applications
alias /rails /var/www/rails/public

<IfModule !mod_fastcgi.c>
  LoadModule fastcgi_module modules/mod_fastcgi.so
</IfModule>
FastCgiServer /var/www/rails/public/dispatch.fcgi -socket /var/tmp/rails.socket
RewriteLog /var/log/rewrite.log
RewriteLogLevel 5
RewriteEngine On

# Skip rest of rewrite if url doesn't start with /rails
# Yes, S=14 is rather fragile, but it's the best we can do at this time
RewriteCond %{REQUEST_URI} !^/rails/?
RewriteRule .* - [S=15]
# Skip rest of rewrite if there is no controller
# Use PT to let mod_alias do the remapping
RewriteCond %{REQUEST_URI} !^/rails(/fcgi/|/mruby/|/)([-_a-zA-Z0-9]+)/
RewriteRule .* - [S=14,PT]
RewriteCond %{REQUEST_URI} ^/rails(/fcgi/|/mruby/|/)([-_a-zA-Z0-9]+)/
RewriteCond /var/www/rails/public/../app/controllers/%2_controller.rb !-f 
RewriteRule .* - [S=13,PT]
# Remove /rails from URL
RewriteRule ^/rails(.*) $1
# Force fcgi
RewriteRule ^/fcgi/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9.]+)$ /var/www/rails/public/dispatch.fcgi?controller=$1&action=$2&id=$3 [L,QSA]
RewriteRule ^/fcgi/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)$ /var/www/rails/public/dispatch.fcgi?controller=$1&action=$2 [L,QSA]
RewriteRule ^/fcgi/([-_a-zA-Z0-9]+)/?$ /var/www/rails/public/dispatch.fcgi?controller=$1&action=sql [L,QSA]
RewriteRule ^/fcgi.* /var/www/rails/public/dispatch.fcgi?controller=dps&action=sql [L,QSA]

# Force mod_ruby
RewriteRule ^/mruby/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9.]+)$ /var/www/rails/public/dispatch.rb?controller=$1&action=$2&id=$3 [L,QSA]
RewriteRule ^/mruby/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)$ /var/www/rails/public/dispatch.rb?controller=$1&action=$2 [L,QSA]
RewriteRule ^/mruby/([-_a-zA-Z0-9]+)/?$ /var/www/rails/public/dispatch.rb?controller=$1&action=sql [L,QSA]
RewriteRule ^/mruby.* /var/www/rails/public/dispatch.rb?controller=dps&action=sql [L,QSA]

# Default rewriting rules. Change extension from .cgi to .fcgi to switch to FCGI and to .rb to switch to mod_ruby
RewriteRule ^/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9.]+)$ /var/www/rails/public/dispatch.cgi?controller=$1&action=$2&id=$3 [L,QSA]
RewriteRule ^/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)$ /var/www/rails/public/dispatch.cgi?controller=$1&action=$2 [L,QSA]
RewriteRule ^/([-_a-zA-Z0-9]+)/$ /var/www/rails/public/dispatch.cgi?controller=$1&action=sql [L,QSA]
RewriteRule .* /var/www/rails/public/dispatch.cgi?controller=sql&action=show [L,QSA]

<Directory /var/www/rails/public>
  AllowOverride none
  Order allow,deny
  Allow from all

  # General Apache options
  AddHandler fastcgi-script .fcgi
  AddHandler cgi-script .cgi
  Options +FollowSymLinks +ExecCGI

  # Remember to set RubySafeLevel 0 in httpd.conf
  <IfModule mod_ruby.c>
    RubySafeLevel 0
    RubyRequire apache/ruby-run
    <Files dispatch.rb>
      SetHandler ruby-object
      RubyHandler Apache::RubyRun.instance
    </Files>
  </IfModule>

  # You can also point these error messages to a controller/action
  ErrorDocument 500 /rails/500.html
  ErrorDocument 404 /rails/404.html
</Directory>

Looks interesting but …
Apache will then automatically load this file? Also I’m not that proficient in configuring Apache and how once I’m using this .conf file what my app directory structure should look like. At this point I don’t have a public dir in /var/www/rails so I’ll create one but then what goes in it?

category: Howto