»Tuesday, November 20, 2007

HOWTO: Setup RoR, Mongrel and Apache on a production server

My experience with setting up production servers was zero before I tried to do this, and I had to go to a lot of sources to find a solution that worked for me. I finally got everyting working smoothly and here's the workflow that I used.

My setup:
-OS: Ubuntu 7.10 (Gutsy Gibbon) Server Edition
-Servers: Apache and Mongrel clusters
-Database: MySQL
-Deployment: Manual (It should be fairly easy to get Capistrano to work, but I am not using SVN and I haven't yet figured out how to integrate my setup with the SCM I currently use)
-RoR Application folder: /home/railsuser/rails/appname/

Step 1: Install Ubuntu Server and follow the instructions to install the LAMP stack (This will install Apache2 and MySQL for you.) It will be easy to reinstall or modify the Apache installation later if required.

Step 2: Install Ruby, Rails and Mongrel
Follow the instructions at http://mongrel.rubyforge.org/docs/debian-sarge.html to install Ruby, Rails, and Mongrel. The basic steps are as follows, but the linked blog provides help for systems that may have extra complications: As root:
  1. Update apt-get
    apt-get update
  2. Install Ruby:
    apt-get install ruby irb rdoc ri ruby1.8-dev libzlib-ruby libmysql-ruby libopenssl-ruby1.8
  3. Install Ruby Gems
    apt-get install rubygems
    (If you need to download rubygems first, use these instructions)
  4. Update your PATH
    In the user account you will use to run this, edit .bashrc (my preferred editor is nano)
    nano ~/.bashrc
    Add the following lines:
    PATH=$PATH:/var/lib/gems/1.8/bin
    export PATH
    Save and exit (^O and ^X should do that in Nano) and at the command prompt, reload your configuration:
    source ~/.bashrc
  5. Installing Mongrel will require some building, so make sure you have the components for that
    apt-get install build-essential
  6. Install Rails and Mongrel:
    gem install rails --include-dependencies
    gem install daemons gem_plugin mongrel mongrel_cluster --include-dependencies
    You will have to pick a version from the list provided. Pick the latest 'ruby' version. This step will take some time.
  7. Configure the Mongrel Cluster
    mongrel_rails cluster::configure -e production -p 8000 -N 2 -c /home/railsuser/rails/appname -a 127.0.0.1
    A note about this:
    -N 2 : Two instances of Mongrel will be started up as part of this cluster
    -p 8000: The Mongrel instances will listen at ports starting at 8000 (i.e. 8000 and 8001)
    /home/railsuser/rails/appname : Path to the folder where your Rails app resides
    -a 127.0.0.1 : This restricts access to localhost. If you are building a server where requests will come from domains other than localhost, do not include this option! I had a tough time figuring out why I could browse my site freely on the linux box, but not from any other machine until I tried removing this option.

    You should see a file mongrel_cluster.yml in the /config/ directory in your Rails application folder. If you need to make changes, use the cluster::configure command instead of directly editing this file.
  8. At this point, you should be able to cd to your Rails application directory (say /home/railsuser/rails/appname) and type in the following command to start up you rails cluster:
    mongrel_rails cluster::start
    You will see a confirmation of mongrel starting up on ports 8000 and 8001. To stop the cluster, just type mongrel_rails cluster::stop. I will update this later to add instructions on how to get mongrel to startup automatically, or you can just try these instructions yourself.
  9. Ensure that you can see your application work at http://yourhost:8000/ and http://yourhost:8001
Step 3: Install and configure Apache
  1. Installing Apache on Ubuntu is simple.
    apt-get install apache2
    However, if you were playing around with Apache and your installation is messed up, you can start afresh as follows:
    apt-get remove --purge apache2.2-common
    apt-get clean
    and then
    apt-get install apache2
  2. If the installation went fine, enable the modules that we need to make Apache work as a front end for the Mongrel cluster
    Instructive way:
    Browse to /etc/apache2/
    All the available modules are in mods-available, while the ones that are enabled are in mods-enabled (duh!) The conf files are the ones that we will look at later to configure apache. The obvious way to enable a module is to create a symbolic link from mods-enabled to mods-available. For example, to enable mod_rewrite, browse to mods-enabled and type (as root):
    ln -s ../mods-available/rewrite.load rewrite.load
    The non-obvious (and easier) way to do the same thing is to use the following commands (this is also a list of the modules we are interested in)
    a2enmod rewrite
    a2enmod proxy
    a2enmod proxy_balancer
    a2enmod proxy_http
  3. Now we need to configure Apache to use the balancer with the mongrel instances we started earlier. Edit /etc/apache2/sites-available/default
    If this is a fresh installation of apache, you don't have any pre-existing site configuration that you care about, so delete every line in this file (otherwise you will get errors about mixing * and *:80 ports) and type in the following (The colored lines are the ones we will have to edit):

    NameVirtualHost *:80

    #
    Add this if necessary
    ServerName myapp

    <Proxy *>
    Order allow,deny
    Allow from all
    </Proxy>

    #Proxy balancer section (Add as many BalancerMembers as you have
    #
    Mongrel servers running
    <Proxy balancer://myapp_cluster>
    BalancerMember http://myapp:8000
    BalancerMember http://myapp:8001
    </Proxy>

    #Virtual host section
    <Virtualhost *:80>
    ServerName myapp
    DocumentRoot
    /home/railsuser/rails/myapp/public/

    <Directory /home/railsuser/rails/myapp/public/ >
    Options Indexes FollowSymLinks MultiViews
    AllowOverride All
    Order allow,deny
    allow from all
    </Directory>

    #log files
    ErrorLog /var/log/apache2/myapp_error.log
    # Possible values include: debug, info, notice, warn, error, crit,
    # alert, emerg.
    LogLevel warn
    CustomLog /var/log/apache2/myapp_access.log combined

    #Rewrite stuff
    RewriteEngine On

    # Check for maintenance file and redirect all requests
    RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
    RewriteCond %{SCRIPT_FILENAME} !maintenance.html
    RewriteRule ^.*$ /system/maintenance.html [L]

    # Rewrite index to check for static
    RewriteRule ^/$ /index.html [QSA]

    # Rewrite to check for Rails cached page
    RewriteRule ^([^.]+)$ $1.html [QSA]

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


  4. Okay, lets's look at the elements we need to change in the above file:
    1. balancer://myapp_cluster:
      Replace myapp_cluster with whatever name you want, but keep it consistent across this file.
      The idea is that when RewriteRule finds a URL that matches the regular expression (say: ^/(.*)$), it will replace it with a value that is represented by balancer://myapp_cluster.
    2. BalancerMember:
      The value of balancer://myapp_cluster is determined by what you put in this section, where you have the paths to two of your mongrel servers. (If you had more than two mongrel servers in your mongrel configuration, you would need to put them in this section too). When a request for a page comes in, Apache will dynamically make a decision about which of your mongrel servers to forward it to.
      So replace BalancerMember http://myapp:8000 with your servername and port for each of the mongrel cluster members.
    3. DocumentRoot
      This is the path to your Rails App.
    4. <Directory /home/railsuser/rails/myapp/public>
      The /public is very important! This is the actual folder that your Rails server serves pages out of. If you forget to put this, expect to see 400 Bad Request messages from Apache.
  5. Restart apache as follows:
    /etc/init.d/apache2 force-reload
    (Later, you can replace force-reload with start/stop/restart, but for now we want to ensure that all the modules we added are loaded)
  6. Your site should be available at http://myhost/. While starting Apache, if you get a warning that the hostname could not be resolved, add the following line in the /etc/apache2/sites-available/default file right after NameVirtualHost *:80
    ServerName myhost
    where myhost is replaced by the actual domain name of your server.
Hopefully I haven't missed anything, but this worked for me, and I hope it does for you too.

Labels: , , , , , ,



...
Anonymous Anonymous says..

Thanks for this guide, very very helpful!
Anonymous Anonymous says..

Great help. Thanks a lot!

Post a Comment

What to do next

Also on this site

Latest Photos

  • www.flickr.com
  • » View Gallery

Stuff I read