Mikenbob.com

January 1, 2007

Apache & Mongrel - Serving the Future of Development

Filed under: Helps and Walkthroughs, Linux Hints, Ruby on Rails — admin @ 8:00 am

My current setup is putting Mongrel behind my Apache server
running mod_proxy_balancer. Why? I am not going to try and convince you, other than saying it’s the best I’ve found (so far). FastCGI crashes too much. The best information can be found at Mongrel’s site.

Introducing Apache + Mongrel

First, be sure you have a working installation of Apache, a working rails application. If not,
go to that walkthrough. If so, feel free to read on!

Because you have already taken a look at Mongrel’s website, you already know that it is NOT the greatest at managing large amounts
of requests. From their FAQ:

Q: Is it multi-threaded or can it handle concurrent requests?
A: Mongrel uses one thread per request,
but it will start closing connections when it gets “overloaded”…

Because of this, and the fact that Apache is a much better overall web-server, we will create a cluster of mongrel servers,
and have apache searve them to mongrel through the mod_proxy_balancer module. (so be sure to have it installed and configured!)

Install Mongrel and Mongel_Cluster

Let’s use gem to install mongrel and mongrel_cluster

$  gem install mongrel mongrel_cluster --include-dependencies

Creating a Mongrel Cluster

mongrel_cluster includes scritps to automatically set up a cluster of servers.

$  mongrel_rails cluster::configure -e production -p 8000 -N 3 -c /var/www/apps/myapp -a 127.0.0.1 --user mongrel --group mongrel
Writing configuration file to config/mongrel_cluster.yml.

Now a configuration file has been created in the RAILS_ROOT/config directory called ‘mongrel_cluster.yml’. Try it out with

$  mongrel_rails cluster::start
Starting 3 Mongrel servers...

I have a startup script installed to start my mongrel servers at boot. To make that happen simply…

$  mkdir /etc/mongrel_cluster
$  ln -s /var/www/apps/myapp/config/mongrel_cluster.yml /etc/mongrel_cluster/myapp.yml
$  cp /path/to/mongrel_cluster_gem/resources/mongrel_cluster /etc/init.d/
$  chmod +x /etc/init.d/mongrel_cluster

And add the script to the system V init

$  /usr/sbin/update-rc.d -f mongrel_cluster defaults

According to the mongrel site…

NOTE At this point there are a few issues with this init script that only apply under certain circumstances. Those issues include:

  • Shebang line - The init script uses #!/usr/bin/env ruby to find the appropriate interpreter. Some distribution installs of ruby only give you a /usr/bin/ruby1.8. You may change the shebang line or simply create a symbolic link from /usr/bin/ruby1.8 to /usr/bin/ruby3.
  • mongrel_cluster_ctl location - If you have installed your gems in /usr/local/ you may find that the init script can not find mongrel_cluster_ctl. To resolve this, you can symbolically link /usr/local/bin/mongrel_cluster_ctl into /usr/bin/

Apache Modules

There are a few required modules to have installed or compiled into your apache configuration. Debian, again, makes this quite easy
with the a2enmod command

$   a2enmod proxy
Module proxy installed; run /etc/init.d/apache2 force-reload to enable.
$   a2enmod proxy_http
Module proxy_http installed; run /etc/init.d/apache2 force-reload to enable.
$   a2enmod proxy_balancer
Module proxy_balancer installed; run /etc/init.d/apache2 force-reload to enable.
$   a2enmod rewrite
Module rewrite installed; run /etc/init.d/apache2 force-reload to enable.
$   a2enmod deflate
Module deflate installed; run /etc/init.d/apache2 force-reload to enable.
$   # Now reload your Apache Configuration
$   /etc/init.d/apache2 reload

You may get messages like the ones below. It’s okay.

This module is already enabled!
Enabling cache as a dependency

Apache VHost Configuration

The cluster setup is just the first step (and I should add, the easiest step). Here’s the fun stuff. Getting Apache to send what
it should to that cluster, and what it should NOT. There is no reason to send images, css files, javascript files, and any other
static file to mongrel. It should only send Ruby on Rails requests. Most of this was learned from the
Mongrel Apache docs, but there is a lot that I did myself. For example,
you can still run PHP sites with this setup.

First, I will show you some highlites. Then, below, you can see the entire vhost file
Again, I am assuming Debian, so each VHost file is it’s own entity. You can make changes where needed.

<Proxy balancer://mongrel_cluster_myapp>
        BalancerMember http://127.0.0.1:8000
        BalancerMember http://127.0.0.1:8001
</Proxy>

You can see that the proxy balancer has a name. That name is mongrel_cluster_myapp. A frequent mistake is creating
two balancers (for two different rails apps) that have the same balancer name. BE CAREFUL! You could spend hours trying to
trouble shoot this!

DocumentRoot /var/www/seminar/public
<Directory /var/www/apps/myapp/public>
    ... dir options here
</Directory>

The DocumentRoot and Home Directory need to be in the public folder.

RewriteEngine On

## Add trailing slash to directories
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} -d
RewriteRule ^(.+[^/])$ $1/ [QSA,R]

## If it's not a file, but index.html exists under that direcory, use that
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME}/index.html -f
RewriteRule ^(.*)$ $1/index.html [QSA]

## If it's not a file, but index.php exists under that direcory, use that
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME}/index.php -f
RewriteRule ^(.*)$ $1/index.php [QSA]

## Rewrite to check for Rails cached page, VERIFY YOUR CLUSTER NAME!!
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-d
RewriteRule ^([^.]+)$ $1.html [QSA]
        # Redirect all non-static requests to cluster
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteRule ^/(.*)$ balancer://mongrel_cluster_myapp%{REQUEST_URI} [P,QSA,L]

## Deflate
AddOutputFilterByType DEFLATE text/html text/plain text/css
# ... text/xml application/xml application/xhtml+xml text/javascript
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4.0[678] no-gzip
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html

And there is the magic! Using Apache Rewrite rules, you can check for .html and .php index files and use those, check
for rails cache files, and finally, if it’s not a static file (image, css, javascript, etc.) pass the request to the Mongrel
Cluster. Because it’s checking for actual files, be sure to put your php files in the public folder. That way, it can see
the file actually exists.

Entire VHost File

<Proxy balancer://mongrel_cluster_myapp>
        BalancerMember http://127.0.0.1:8000
        BalancerMember http://127.0.0.1:8001
</Proxy>

NameVirtualHost *:80
<VirtualHost *:80>

        ServerName myapp.example.com
        DocumentRoot /var/www/apps/myapp/public

        #### HOME DIRECTORY ####
        <Directory /var/www/apps/myapp/public>
                Options FollowSymLinks
                AllowOverride all
                Order allow,deny
                Allow from all
        </Directory>
        ### END HOME ###

        ### REWRITES ###
        RewriteEngine On

        # Uncomment for rewrite debugging
        #RewriteLog /var/www/apps/myapp/myapp_rewrite_log
        #RewriteLogLevel 9

        ## Add trailing slash to directories
        RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} -d
        RewriteRule ^(.+[^/])$ $1/ [QSA,R]

        ## If it's not a file, but index.html exists under that direcory, use that
        RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
        RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME}/index.html -f
        RewriteRule ^(.*)$ $1/index.html [QSA]

        ## If it's not a file, but index.php exists under that direcory, use that
        RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
        RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME}/index.php -f
        RewriteRule ^(.*)$ $1/index.php [QSA]

        # Rewrite to check for Rails cached page
        RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-d
        RewriteRule ^([^.]+)$ $1.html [QSA]

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

        # Deflate
        AddOutputFilterByType DEFLATE text/html text/plain text/css
        # ... text/xml application/xml application/xhtml+xml text/javascript
        BrowserMatch ^Mozilla/4 gzip-only-text/html
        BrowserMatch ^Mozilla/4.0[678] no-gzip
        BrowserMatch \bMSIE !no-gzip !gzip-only-text/html

        # this not only blocks access to .svn directories, but makes it appear
        # as though they aren't even there, not just that they are forbidden
        <DirectoryMatch "^/.*/\.svn/">
                ErrorDocument 403 /404.html
                Order allow,deny
                Deny from all
                Satisfy All
        </DirectoryMatch>

        ### SERVER SETTINGS ###
        ErrorLog /var/log/apache2/error.log

        # Possible values include: debug, info, notice, warn, error, crit,
        # alert, emerg.
        LogLevel warn

        CustomLog /var/log/apache2/access.log combined
        ServerSignature On

</VirtualHost>

Ruby on Rails Installation - Linux

Filed under: Helps and Walkthroughs, Linux Hints, Ruby on Rails — admin @ 8:00 am

My current web-development method of choice is Ruby on Rails. Here, I will show you how
to install it when running the latest Debian server.

Initial Installation

I am running a Debian box currently. I had many problems trying to install and run rails without errors. The following is what
I did to make it work. These steps assume root access. If you don’t have it, try sudo.

NOTICE: I take no responsibility for you messing up your systems. Please back up everything before attempting to follow these
steps. I worked for me!

Prep for installation

I had to have build-essintial installed. It wasn’t included in my initial install

$  apt-get install build-essential

Install Ruby

apt-get works for these:

$  apt-get install ruby libruby1.8 ruby1.8 ruby1.8-dev

Prep for Gems

Not sure why, but I couldn’t install gems without these:

$  apt-get install irb1.8 libgems-ruby1.8 libopenssl-ruby1.8 libreadline-ruby1.8 rdoc1.8

Install Gems

If using Debian, you can install rubygems with apt-get. Run this command, then skip to update.

$  apt-get install rubygems

Not on Debian? Most people would be able to start right here! I liked the actual install of gems from a file. I’m not sure if apt-get gems works or not.

$  # Download/Extract RubyGems @ http://rubyforge.org/frs/?group_id=126

$  wget http://rubyforge.org/frs/download.php/????/rubygems-X.X.X.tgz # Please go to the site for the actual download
$  tar xzvf rubygems-X.X.X.tgz
$  cd rubygems-X.X.X.tgz
$  ruby setup.rb

Update

It’s a good time to update your system configuration now:

$  gem update
$  gem update --system

Install Rails

Now, install Rails from Gem

$  #gem install -v=1.2.2 rails --include-dependencies # If you want a particular version...
$  gem install rails --include-dependencies

Next step… Making Apache work with Mongrel

Apache & Mongrel - Serving the Future of Development

Copyright © 2006 All rights reserved

Powered by WordPress