A collection of computer systems and programming tips that you may find useful.
 
Brought to you by Craic Computing LLC, a bioinformatics consulting company.

Thursday, January 25, 2007

Configuration of Web Servers and Rails

When it comes to setting up a web server to host a Rails application, there are a number of choices. Unfortunately, the documentation and HOWTOs that describe these options can be confusing, often getting bogged down in the details of compiling pieces of code, etc.

This note an attempt to present the range of options and to guide you through the installation of each. In summary, your choices are:
1. WEBrick - built into Rails
2. Apache
3. Apache with FastCGI - higher performance
4. Lighttpd - a fast alternative to Apache
5. Lighttpd with FastCGI
6. Mongrel - a server written in Ruby
7. A Hybrid Solution

Lighttpd with FastCGI is a common solution for production Rails servers. Apache is the most common server on the Internet but as you will see there are issues in using it compared to the alternatives. Mongrel is a relative newcomer that is getting a lot of attention.

The installation steps given here are for Linux Fedora Core 5 but these will likely apply to other current Unix variants.

1: WEBrick

The simplest option is to use the WEBrick server that is built into each Rails installation. You don't have to install anything over and above regular Rails.

From a terminal, cd to the top level directory of your application and run:
# script/server
By default this runs a server on localhost (i.e. locally to that machine) on port 3000. Point a browser on that machine to http://localhost:3000 and you should see your application. There is no configuration file.

This is great for development, but doesn't cut it if you want anyone else to use your application.

2: Apache

Most Linux installations will already have the Apache httpd server installed and ready to run. Perhaps the easiest way to see if it is running is (as root):
# /sbin/service httpd status
You can start, stop or restart it with
# /sbin/service httpd start
# /sbin/service httpd stop
# /sbin/service httpd restart
The default configuration file for Apache (/etc/httpd/conf/httpd.conf) needs to be modified in order to run a Rails application. Make a backup copy of the file before you make any changes!

Open the file in an editor, look for these two LoadModule lines and make sure they are not commented out:
LoadModule env_module modules/mod_env.so
LoadModule rewrite_module modules/mod_rewrite.so
Then go to the bottom of the file and add the following block, replacing MYAPP with the path to your application directory:
<VirtualHost *:80>
SetEnv RAILS_ENV development

DocumentRoot /MYAPP/public/
ErrorLog /MYAPP/log/apache.log

<Directory "/MYAPP/public">
Options ExecCGI FollowSymLinks
AddHandler cgi-script .cgi
AllowOverride all
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
Now when you restart Apache and point your browser to http://localhost (you don't need the :3000 here), or its real hostname from a browser on a different machine, you should get the Rails welcome page.

If you get a '403' page telling you that you don't have permission then make sure that all the directories including and above the application directory are world-readable.

So now you have the application running under Apache. Apache is great but does not give you the highest performance possible. You can improve its response by adding in the FastCGI module.

3: Apache + FastCGI

This is typically where the HOWTOs get really confusing, really quickly...

The bottom line is that, for now, you might find another one of the server options an easier path than this one.

FastCGI is an extension to CGI that greatly improves server performance. You can learn more and download it from http://www.fastcgi.com.

You will need to download and compile two components - fcgi, which is the 'core' FastCGI software - and mod_fastcgi, the Apache module component that links fcgi and the web server.

You should be root when you install all the following packages.

Before doing this, make sure you have these Apache development packages installed. They may not all be necessary, but play it safe. Install them like this:
# yum install httpd-devel apr apr-devel apr-util-devel
The following assumes that you can use wget to fetch remote files. If not, fetch them with your browser. Download and compile in a temporary or scratch directory. You might want to check for newer versions of these files, but they have not changed since 2003.

Install the software under /usr/local to isolate it from general Linux software.

To install fcgi:
# wget http://www.fastcgi.com/dist/fcgi-2.4.0.tar.gz
# tar -zxvf fcgi-2.4.0.tar.gz
# cd fcgi-2.4.0
# ./configure --prefix=/usr/local
# make
# make install
If this all works as expected then you'll be able to see a bunch of libfcgi files in /usr/local/lib.

Now you need to install a ruby gem that allows it to use fcgi. You need to tell it where the fcgi libraries and include files are installed.
# gem install fcgi -r -- --with-fcgi-lib=/usr/local/lib --with-fcgi-include=/usr/local/include


Next you install the mod_fastcgi module for Apache... and here's the problem...

At the time of writing (January 2007) the current version mod_fastcgi-2.4.2 does NOT COMPILE with Apache 2.2. The solution requires you to patch the mod_fastcgi source.. messy, very messy... I've written a separate post that will guide you through the process: Compiling mod_fastcgi-2.4.2 for Apache 2.2. I will do my best to update this post if and when the problem is fixed.

Those instructions show you how to patch the source, compile the source and update the httpd.conf file.

If you have been brave, or foolhardy, enough to go through all that rigmarole then there is just two more steps left before your Rails app can utilize the performance boost that FastCGI offers.

In your Rails application directory, go to public and edit the .htaccess file. Change the line:
RewriteRule ^(.*)$ dispatch.cgi [QSA,L]
to
RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
Restart Apache and you should be good to go...

Finally, check that the log directory in your application is world-writeable so that fcgi can create a file called fastcgi.crash.log

4: Lighttpd

Lighttpd (aka LightTPD and pronounced 'lighty') is an alternative to Apache that offers many of the same features but with smaller resource requirements and higher performance. It has been long favored by the Rails community, although Mongrel is challenging that status.

Before you start, make sure that you have /usr/local/sbin in your path. You can put this line in the .bash_login file for each user, or in /etc/profile to set up all users:
export PATH="/usr/local/sbin:$PATH"
. Start a new shell to make sure you pick up the new PATH.

Installation is straightforward, but it does have a prerequisite in the PCRE library which is used for regular expression pattern matching. Install PCRE and Lighttpd into /usr/local. You will see a ton of compile commands and warnings but don't worry.

Note the CFLAGS option. This was included in Dan Benjamin's install instructions for Mac OS X and is needed for Intel Macs. You may not need it, but it'll do no harm. The option is written as 'Oh-One' not 'Zero-One'.
# wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-6.6.tar.gz
# tar -zxvf pcre-6.6.tar.gz
# cd pcre-6.6
# ./configure --prefix=/usr/local CFLAGS=-O1
# make
# make install
Now fetch the lighttpd distribution (check for a more recent version first) and install it thus:
# wget http://www.lighttpd.net/download/lighttpd-1.4.13.tar.gz
# tar -zxvf lighttpd-1.4.13.tar.gz
# cd lighttpd-1.4.13
# ./configure --prefix=/usr/local --with-pcre=/usr/local
# make
# make install
The lighttpd executable is located at /usr/local/sbin/lighttpd

Assuming that you already had Apache installed on your system, you will need to replace references to it in your system startup scripts, and you will need to modify the lighttpd config file to use your Rails application.

On Linux the httpd startup script is /etc/rc.d/init.d/httpd. Make a backup copy of this before you start messing with it. You need to replace all references to the Apache httpd with the lighttpd equivalents. To avoid cluttering this post, I've put a lighttpd specific startup file on my site HERE. You can also look at the script rc.lighttpd included in the doc subdirectory of the lighttpd source distribution.

The one line that you will need to change is the location of the lighttpd config file. If you only plan to run a single Rails app on your system then you can use the one in your application directory tree. Otherwise you need to place one in a suitable location such as /etc/httpd/conf/lighttpd.conf.

Detailed help on the config file can be found HERE, but for a Rails application you should start with the lighttpd.conf file in your application config directory.

What's that? You don't have lighttpd.conf in your config directory? Rails will take care of that for you!

Assuming you have /usr/local/sbin in your PATH, go to the Rails App directory and start the built-in server thus:
# script/server
=> Booting lighttpd (use 'script/server webrick' to force WEBrick)
=> config/lighttpd.conf not found, copying from
/usr/lib/ruby/gems/1.8/gems/rails-1.2.1/configs/lighttpd.conf
=> Rails application starting on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server (see config/lighttpd.conf for options)
Rails detects lighttpd in your path and uses that in preference to WEBrick. Not only that but it will copy a lighttpd.conf file into your config directory if it doesn't see one. Pretty neat...

To serve this application to users on other machines you will want to copy this local config file and modify it.

The two most important lines in that file are at the beginning:
server.bind = "0.0.0.0"
server.port = 3000
These tell the server to just respond to requests on that machine (localhost) on port 3000. This is the default for the development server. Change these to the real hostname of the machine and port 80.

Next you need to change all references to CWD to the real path to that directory (/proj/rails/myapp for example).

Reference this file in the lighttpd startup script, restart the server and go to that URL in a browser on this or another machine. You should see the Rails app welcome page. You're up and running with lighttpd!

5: Lighttpd + FastCGI

You can add performance to a lighttpd server using FastCGI, just like you can with Apache, although setting it up is much easier. Before you install lighttpd, install the fcgi software as described in the Apache + FastCGI section, install the fcgi gem but do not go through all the mod_fastcgi nonsense! The lighttpd installation comes with its own mod_fastcgi module.

Lighttpd picks up on the fact that you have fcgi installed and makes use of it. You'll see it referenced in the lighttpd.conf file that Rails sets up for you.

6: Mongrel

Mongrel is a web server written in Ruby (with C) that is extremely easy to get running and that plays well with Rails.

Installation involves nothing more than installing a gem.
# gem install mongrel
But note that at the time of writing (01/25/2007) Mongrel 1.0.1 requires Ruby 1.8.4 and does not install on Ruby 1.8.5.

You can run mongrel as a local development server. Instead of running script/server:

# cd myrailsapp
# mongrel_rails start
Its performance is apparently faster than WEBrick and it does not need a configuration file in many cases.

One advantage it offers over other solutions in production systems is a simple way to setup clusters of servers that can help load balancing. But that is beyond the scope of this note.

7: A Hybrid Solution

You would not use Mongrel by itself as a production server. Instead you combine it with Apache (or lighttpd). Apache acts as the front end, proxying certain requests on to mongrel. This hybrid solution may appear complex but it allows you to utilize the best features of both servers. Apache is better at serving static content like stylesheets and images, whereas mongrel will be better at serving dynamic content coming from your Rails application. Setting this up seems fairly straightforward. Check the mongrel web site for details and examples.

Similarly you can combine Apache and lighttpd by adding ProxyPass directives to an Apache configuration. You might want to do this if your server already hosts a site under Apache that you don't want to change. You can add in a Rails application linked to lighttpd on a different port with Apache as the front end, redirecting requests or processing them as appropriate.

An example configuration block is:
<VirtualHost *:80>
ServerName myapp.com
ServerAlias www.myapp.com

ProxyPass / http://www.myapp.com:8000/
ProxyPassReverse / http://www.myapp.com:8000
ProxyPreserveHost on
</VirtualHost>
This redirects all requests to the virtual host to a second server running on port 8000.



A Note About Sources of Information

This note is the result of reading a lot of HOWTOs and notes about web server installation, a lot of experimentation and quite a bit of frustration.

The Ruby on Rails site lists many such documents, but some of these are confusing and/or outdated - caveat emptor.

Some of the useful documents for me have been:
Rails on lighttpd - Duncan Davidson
Building Ruby, Rails, LightTPD, and MySQL on Tiger - Dan Benjamin
Ruby on Rails (with FastCGI) Howto - "goldenratio"
Thanks to those authors and others who have helped guide me through some of the thorny installation issues.

No comments:

Archive of Tips