Tuesday, March 14, 2006

Setup single or multiple RoR applications on an Apache2, FastCGI, Debian Sarge linux server

This blog is about to take (yet another) technical turn. I have been eating, breathing, and sleeping RoR (Ruby on Rails) and have found dozens of helpful tutorials. Using many of these tutorials I was able to figure out how to setup single or multiple RoR applications on a Debian Sarge linux server.

Why Did I Make This? Does it Really Work?

This is what worked for me. I've used it three times so far. (and it gets better and more correct each time!) It may not work for you. You may have to modify some things to get it to work. If you have any ideas on how this howto can improve please comment. This is posted for the good of the RoR community. I have learned that many (including me) have found it difficult to get RoR working on Debian with Apache2 with FastCGI. I make no assertions that these methods will help you. I cannot be held liable for any damage they cause. You follow them at your own risk. I started with a clean install so that no customizations get in the way. Theoretically if you flatten a box and follow these steps you'll have a working Rails server soon.

WARNING: I have not addressed security at all (such as setting a MySQL root password). You have now been warned.

My Environment

The webserver is named 'webdemo', and the client machine is named 'galaxy'. Both are running Debian Sarge, though the client machine just needs a web browser, so OS is irrelevant.

For this demonstration I am using the source for SimpleTicket, an open source GPLed ticketing system on rails. It is currently two rails applications which both need to be served by a CGI enabled webserver. The two apps are named "stadmin", and "tt". See http://www.simpleticket.net/ for more info.

It Doesn't Work!

I am aware that for Debian on platforms other than i386 this howto needs some modification. I am working on making it work for PowerPC right now.

Start your Engines
(a.k.a. turn on the computers)

Perform a stardard Debian Sarge 'netinstall'.
Choose the "Web Server", and "SQL Server" setup options.
A GUI is not required.

For good measure:

webdemo:~# apt-get update


If you like nano (or some other text editor) better than vim then everywhere you see vi or vim instert your favorite text editor. I'll be using vim since that is what I grew up on.

Install Packages

webdemo:~# apt-get install ruby libzlib-ruby rdoc irb curl libapache2-mod-fcgid libfcgi-ruby1.8 libmysql-ruby subversion ruby1.8-dev vim


Install MySQL 5

The next few steps will only work if there are unofficial .deb's for MySQL 5 for Debian on your specific processor. If your processor doesn't have the .debs, like the PPC processor family, fear not, there is another way (and it might be easy!) - skip to "Install MySQL 5 on PowerPC and other non-monopoly chipsets".

Add two or three lines to /etc/apt/sources.list (for more info on why this must be done see: http://www.debian-administration.org/articles/357/print):

webdemo:~# vi /etc/apt/sources.list
# Use dotdeb.org for LAMP related packages not available in Sarge
deb http://dotdeb.pimpmylinux.org/ stable all
deb-src http://dotdeb.pimpmylinux.org/ stable all


Update apt with the dotdeb's:

webdemo:~# apt-get update


Install MySQL 5:

webdemo:~# apt-get install mysql-server


When you are done you may want to remove or comment out the lines you added so you don't mess up other installations with non-Debian approved packages:

webdemo:~# vi /etc/apt/sources.list
# Use dotdeb.org for LAMP related packages not available in Sarge
#deb http://dotdeb.pimpmylinux.org/ stable all
#deb-src http://dotdeb.pimpmylinux.org/ stable all


Update apt without the dotdeb's:

webdemo:~# apt-get update


Install MySQL 5 on PowerPC and other non-monopoly chipsets


Replace the MYSQL-VERSION-OS with your own MySQL, Version, and OS. In this example I am using 5.0.19 and linux-powerpc:


webdemo:~# groupadd mysql
webdemo:~# useradd -g mysql mysql
webdemo:~# cd /usr/local
webdemo:/usr/local# curl -O http://mysql.mirrors.hoobly.com/Downloads/MySQL-5.0/mysql-max-5.0.19-linux-powerpc-glibc23.tar.gz

THEN THIS (If you downloaded the file into some other directory)
webdemo:/usr/local# gunzip < /PATH/TO/MYSQL-VERSION-OS.tar.gz | tar xvf -
webdemo:/usr/local# ln -s /PATH/TO/MYSQL-VERSION-OS mysql

OR THIS (if you did as I did)
webdemo:/usr/local# tar -zxvf mysql-max-5.0.19-linux-powerpc-glibc23.tar.gz
webdemo:/usr/local# ln -s /usr/local/mysql-max-5.0.19-linux-powerpc-glibc23 mysql

CONTINUING...
webdemo:/usr/local# ln -s /usr/local/mysql-max-5.0.19-linux-powerpc-glibc23 mysql
webdemo:/usr/local# cd mysql
webdemo:/usr/local/mysql# scripts/mysql_install_db --user=mysql
webdemo:/usr/local/mysql# chown -R root .
webdemo:/usr/local/mysql# chown -R mysql data
webdemo:/usr/local/mysql# chgrp -R mysql .
webdemo:/usr/local/mysql# cd ~
webdemo:~# vi .bashrc
# add the following lines (to whatever is already there) save and quit (type ":wq" after editing):
PATH="$PATH:/usr/local/mysql/bin"
export PATH

Then source the .bash_rc (or log out and log back in)
webdemo:~# source .bash_rc

Start the MySQL server!
webdemo:/usr/local/mysql# bin/mysqld_safe --user=mysql &



Install and Setup Rails


webdemo:~# curl -O http://rubyforge.org/frs/download.php/5207/rubygems-0.8.11.tgz
webdemo:~# tar -zxvf rubygems-0.8.11.tgz && cd rubygems-0.8.11 && ruby setup.rb all && cd ..
webdemo:~# gem install rails feedtools --include-dependencies
webdemo:~# wget http://www.fastcgi.com/dist/fcgi.tar.gz
webdemo:~# tar -zxvf fcgi-2.4.0.tar.gz && cd fcgi-2.4.0 && ./configure && make && make install
webdemo:~# gem install fcgi --include-dependencies && cd ..
webdemo:~# mkdir /var/rails && chown -R www-data:www-data /var/rails &&chmod -R g+w /var/rails && chmod u+s,g+s /var/rails && cd /var/rails


Get Source Of Your Rails Application

Somehow get your Rails source into this directory or create your own rails app by doing one of the following 3 things (my example uses SimpleTicket):
1)
do this:
pboling@galaxy:~$ scp SimpleTicket.tar.gz root@webdemo:/var/rails

or this:
webdemo:/var/rails# wget http://superb.dl.sourceforge.net/sourceforge/simpleticket/SimpleTicket.tar.gz

then this:
webdemo:/var/rails# tar -zxvf SimpleTicket.tar.gz


2)
webdemo:/var/rails# mkdir /var/SimpleTicket && cd /var/SimpleTicket && svn co svn://project.simpleticket.net/trunk && mv stadmin ../../rails/ && mv tt ../../rails/ && cd /var/rails


IF you chose the third mothod, then you need to think of 'myrailsapp' wherever simpleticket is mentioned.
3)
webdemo:/var/rails# rails myrailsapp


Import the SQL Dump

Now might be the time to create one if you don't have one!

IF your db is NOT created and selected by the sql dump/import file:

webdemo:/var/rails# mysqladmin -p create simpleticket && mysql -u root -p simpleticket < /var/rails/stadmin/db/ttdb.sql


OR if your db is created and selected by the sql dump/import file:

webdemo:/var/rails# mysql -u root < /var/rails/stadmin/db/TimeTicket.sql


Explain the Database Connection to Rails


webdemo:~# vi /var/rails/stadmin/config/database.yml
development:
adapter: mysql
database: simpleticket
port: 3306
socket: /var/run/mysqld/mysqld.sock
host: localhost
username: root
password:

# Warning: The database defined as 'test' will be erased and
# re-generated from your development database when you run 'rake'.
# Do not set this db to the same as development or production.
test:
adapter: mysql
database: simpleticket
port: 3306
socket: /var/run/mysqld/mysqld.sock
host: localhost
username: root
password:

production:
adapter: mysql
database: simpleticket
port: 3306
socket: /var/run/mysqld/mysqld.sock
host: localhost
username: root
password:


If the same database is used by multiple applications (as in this example) then you can copy the database.yml file to your other apps using the database.

webdemo:/var/rails# cp /var/rails/stadmin/config/database.yml /var/rails/tt/config/database.yml


Setup Apache to Serve Your Rails Apps



webdemo:/var/rails# vi /etc/apache2/sites-available/default
webdemo:/var/rails# cat /etc/apache2/sites-available/default
# The IP should be the IP of the server hosting this/these site(s). After the colon, ':', is the port you have Apache2 running on. Normally this is 80.
NameVirtualHost 192.168.160.189:80

(less than sign)VirtualHost 192.168.160.189:80(greater than sign)
#This is the web address that you will access the site with. It helps if this address is in DNS already, but adding it to your /etc/hosts file will allow you to access it as well.
ServerName simple-ticket-admin-demo.somecompany.com

DocumentRoot /var/rails/stadmin/public/
CustomLog /var/log/apache2/referer_log combined

# Note that you can't put this in the .htaccess
DefaultInitEnv RAILS_ENV production
(less than sign)Directory /var/rails/stadmin/public/(greater than sign)
Options ExecCGI +FollowSymLinks
AllowOverride All
order allow,deny
allow from all
(less than sign)/Directory(greater than sign)
(less than sign)/VirtualHost(greater than sign)

# If you want more virtual hosts (with name-based routing) then repeat everything in (less than sign)VirtualHost(greater than sign) tags for each host (i.e. do not repeat the first line of the file that says "NameVirtualHost 192.168.160.189:80"
# For example if you have another rails app, (like 'tt' in SimpleTicket version 1) you would add (uncommented) the following:

#Notice the IP is the same as for the site above. This is name-based routing.
#(less than sign)VirtualHost 192.168.160.189:80(greater than sign)
# ServerName customer-ticket.somecompany.com
#
# DocumentRoot /var/rails/tt/public/
# CustomLog /var/log/apache2/referer_log combined
#
# # Note that you can't put this in the .htaccess
# DefaultInitEnv RAILS_ENV production
# (less than sign)Directory /var/rails/tt/public/(greater than sign)
# Options ExecCGI +FollowSymLinks
# AllowOverride All
# order allow,deny
# allow from all
# (less than sign)/Directory(greater than sign)
#(less than sign)/VirtualHost(greater than sign)(less than sign)/blockquote(greater than sign)


Setup Apache's Access Rules




webdemo:/var/rails# vi /var/rails/stadmin/public/.htaccess
webdemo:/var/rails# cp /var/rails/stadmin/public/.htaccess /var/rails/tt/public/.htaccess
webdemo:/var/rails# cat /var/rails/stadmin/public/.htaccess
RewriteEngine On
# General Apache options
#AddHandler fastcgi-script .fcgi
#AddHandler cgi-script .cgi
AddHandler fcgid-script .fcgi
Options +FollowSymLinks +ExecCGI

# If you don't want Rails to look in certain directories,
# use the following rewrite rules so that Apache won't rewrite certain requests
#
# Example:
# RewriteCond %{REQUEST_URI} ^/notrails.*
# RewriteRule .* - [L]

# Redirect all requests not available on the filesystem to Rails
# By default the cgi dispatcher is used which is very slow
#
# For better performance replace the dispatcher with the fastcgi one
#
# Example:
# RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]

# If your Rails application is accessed via an Alias directive,
# then you MUST also set the RewriteBase in this htaccess file.
#
# Example:
# Alias /myrailsapp /path/to/myrailsapp/public
# RewriteBase /myrailsapp

RewriteRule ^$ index.html [QSA]
RewriteRule ^([^.]+)$ $1.html [QSA]
RewriteCond %{REQUEST_FILENAME} !-f
#RewriteRule ^(.*)$ dispatch.cgi [QSA,L]
RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]

# In case Rails experiences terminal errors
# Instead of displaying this message you can supply a file here which will be rendered instead
#
# Example:
# ErrorDocument 500 /500.html

ErrorDocument 500 "Application Error. Rails application failed to start properly"


Link FastCGI Modules to Apache

webdemo:/var/rails# cd /etc/apache2/mods-enabled && ln -s ../mods-available/fcgid.* . && ln -s ../mods-available/rewrite.* . && cd /var/rails


Restart Apache


webdemo:/var/rails# /etc/init.d/apache2 restart


Now you should be able to access your webapp at the web address you chose, as long as the SeverName set in the sites-available directory is in DNS. Otherwise you'll need to add it to your /etc/hosts file (this is useful for development, but not for production!). Here are some parts of my /etc/hosts file (NOT the /etc/hosts file of the webserver, but of the machine that will be accessing the webserver):

pboling@galaxy:~$ cat /etc/hosts
127.0.0.1 localhost.localdomain localhost galaxy

###########################################################
# Development Sites on my Webserver
###########################################################
192.168.160.189 simple-ticket-admin-demo.somecompany.com simple-ticket-admin-demo
192.168.160.189 customer-ticket.somecompany.com customer-ticket

# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts

1 hashings:

Zimm said...

you have officially gone of the deep end.

:)

This blog began on Monday, September 27, 2004.
Hits since 2/20/2007:
free hit counters
free hit counters