Posted by Vince Wadhwani on Jan 09, 2008

This is a follow-up to my article on Installing Ruby on Rails for Nginx. It can also be a good jumping point for another of other Ruby frameworks such as Merb.

Although I'm a big fan of the golden path, sometimes you just don't have the option of picking and choosing your components. Recently I had to deploy a rails app alongside PHP using Apache 2. I took some notes during the process -- hopefully they come in handy for a few of you.

Step 1: Update your system and get rid of packages you no longer need. Do that by running:

sudo apt-get update
sudo apt-get dist-upgrade
sudo apt-get autoremove

Step 2: We'll be installing some software that needs to be built so we'll need to get packages required for compiling. In one swoop, you can type this command and get everything you need:

sudo apt-get install build-essential

I believe the build-essential package is Ubuntu only, so if you're running another Debian variety you may need to do some searching. I believe the required tools were already there with Sidux.

Step 3: Let's grab mysql and ruby. If you go with postgres or sqlite you can replace the mysql packages with the appropriate packages.

sudo apt-get install mysql-server mysql-client libmysqlclient15-dev libmysql-ruby1.8 ruby1.8-dev ruby1.8 ri1.8 rdoc1.8 irb1.8 libreadline-ruby1.8 libruby1.8 libopenssl-ruby irb1.8 libdbd-mysql-perl libdbi-perl libmysql-ruby1.8 libmysqlclient15-dev libmysqlclient15off libnet-daemon-perl libopenssl-ruby libopenssl-ruby1.8 libplrpc-perl libreadline-ruby1.8 libruby1.8 mysql-client mysql-client-5.0 mysql-common mysql-server mysql-server-5.0 rdoc1.8 ri1.8 ruby1.8 ruby1.8-dev zlib1g-dev

You'll be prompted for a root password for mysql. You should enter one.. leaving it blank is a *very bad idea*.

Now for some reason, the symlinks didn't get properly created for me when I ran the above commands on Gutsy Server version (this may be a new policy as it happens in Debian too). To fix that, run these commands:

sudo ln -s /usr/bin/ruby1.8 /usr/local/bin/ruby
sudo ln -s /usr/bin/rdoc1.8 /usr/local/bin/rdoc
sudo ln -s /usr/bin/ri1.8 /usr/local/bin/ri
sudo ln -s /usr/bin/irb1.8 /usr/local/bin/irb

After you're done you should be able to see your ruby version by just typing ruby -v instead of ruby1.8 -v. Do that now and make sure your ouput is at least Ruby 1.8.6!

Step 4: Install Ruby Gems. The last time I wrote a howto we were at version 0.9.4 of Ruby Gems. Thankfully we've gotten a nice update to 1.0.1 so go ahead and download that to your server now. Once done, we'll unpack and run the setup. Note that the file in the wget line may change over time so your best bet is to head over to rubyforge and grab the latest tarball!

wget http://rubyforge.org/frs/download.php/29548/rubygems-1.0.1.tgz
tar xvzf rubygems-1.0.1.tgz
cd rubygems-1.0.1
sudo ruby setup.rb

Once again we'll want to create a symlink so we can access all our gems the way we're used to:

sudo ln -s /usr/bin/gem1.8 /usr/bin/gem

For good measure, type gem -v and make sure you get proper output for the version of gems you downloaded.

With that done, let's go to Step 5: grab rails!
sudo gem install rails

Unlike the previous HowTo's we don't have to use the --include-dependencies switch.. it's now built in for us with Rubygems 0.9.5 and later. It's also quite cool that they finally fixed that ERROR: While executing gem issue. Yep, if you've done everything above, rails should pretty much install smoothly.

Step 6: Let's grab mongrel now. There are other possibilities on the horizon but as of this writing mongrel is still the way to go.

sudo gem install mongrel

You may also notice that you're no longer prompted for your architecture or the version to install. Gems got much much smarter on us!

At this point you've got a working Ruby on Rails application for Gutsy. We still need to setup the webserver and php (in a minute) but first let's test out your sweetly installed goods by creating a web app and running it with mongrel:

cd ~/
rails my_test_app
cd my_test_app
ruby script/server

If all goes well you'll see this familiar output:

=> Booting Mongrel (use 'script/server webrick' to force WEBrick)
=> Rails application starting on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
** Starting Mongrel listening at 0.0.0.0:3000
** Starting Rails with development environment...
** Rails loaded.
** Loading any Rails specific GemPlugins
** Signals ready.  TERM => stop.  USR2 => restart.  INT => stop (no restart).
** Rails signals registered.  HUP => reload (without restart).  It might not work well.
** Mongrel 1.1.3 available at 0.0.0.0:3000
** Use CTRL-C to stop.

Indeed, wandering over to port 3000 on your server should present you with the welcome to rails placeholder page. (Don't forget to erase that from the public directory when you're ready to start coding!)

Hit control-c to exit mongrel and let's continue with our setup. In Step 7 we're going to get Apache2 and optionally PHP5.

sudo apt-get install apache2 apache2.2-common apache2-mpm-prefork apache2-utils libexpat1 ssl-cert libapr1 libaprutil1 libmagic1 libpcre3 libpq5 openssl

If you're so inclined, go ahead and grab php5 and phpmyadmin:

sudo apt-get install autoconf automake1.4 autotools-dev defoma file fontconfig-config libaspell15 libcurl3 libfontconfig1 libfreetype6 libgd2-xpm libice6 libjasper1 libjpeg62 liblcms1 libltdl3 libmagick9 libmcrypt4 libmhash2 libpng12-0 libsensors3 libsm6 libsnmp-base libsnmp10 libsqlite0 libssl-dev libt1-5 libtiff4 libtool libx11-6 libx11-data libxau6 libxdmcp6 libxext6 libxml2 libxpm4 libxslt1.1 libxt6 m4 shtool ttf-dejavu ttf-dejavu-core ttf-dejavu-extra ucf x11-common libapache2-mod-php5 php5 php5-common php5-curl php5-dev php5-gd   php5-imagick php5-mcrypt php5-memcache php5-mhash php5-mysql php5-pspell php5-snmp php5-sqlite php5-xmlrpc php5-xsl phpmyadmin

If you're skipping phpmyadmin, then install all the above packages except the one that says phpmyadmin.. If you do install phpmyadmin you'll be prompted to autoconfigure a webserver. Go ahead and choose to autoconfigure Apache2 so we can save ourselves some time.

Step 8: Configure apache for mongrel cluster by first enabling some mods:

sudo a2enmod rewrite
sudo a2enmod proxy
sudo a2enmod proxy_balancer
sudo a2enmod proxy_http

After each one of those commands you'll likely see something that says Module 'foo' installed run /etc/init.d/apache2 force-reload to enable. So let's do that:

sudo /etc/init.d/apache2 force-reload

Whoa, it worked but we got some funky output:

apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.0.1 for ServerName

Let's fix that by opening up the config file and giving our server a name by adding this line to the bottom /etc/apache2/apache2.conf (You can call the server anything you like.. I promise I won't be sad if you don't call it puddler!) You'll also want to add the Virtual Hosts line otherwise you won't be able to have multiple sites running at the same time. The error is something like [warn] _default_ VirtualHost overlap on port 80, the first has precedence

ServerName puddler
#Added by Vince for Virtual Hosts
NameVirtualHost *:80
<IfModule mod_ssl.c>
    NameVirtualHost *:443
</IfModule>

Reload again and you should see the warning is gone.

Step 9: Let's get mongrel_cluster installed and configured.

sudo gem install mongrel_cluster
sudo cp /usr/lib/ruby/gems/1.8/gems/mongrel_cluster-1.0.5/resources/mongrel_cluster /etc/init.d/mongrel_cluster

Next, add a path statement to mongrel_cluster file just above the CONF_DIR variable in /etc/init.d/mongrel_cluster

PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local:/usr/local/sbin:/usr/local/bin

I like to run mongrel as user www-data. In the etc/init.d/mongrel cluster file you'll find the lines you need to modify if you want to follow along.

sudo vi /etc/init.d/mongrel_cluster

make sure it contains these lines:

PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local:/usr/local/sbin:/usr/local/bin
CONF_DIR=/etc/mongrel_cluster
PID_DIR=/var/run/mongrel_cluster
USER=www-data

Next, make it executable and start it on boot:

sudo chmod +x /etc/init.d/mongrel_cluster
sudo update-rc.d mongrel_cluster defaults

We're not quite done yet -- we need to setup the mongrel cluster correctly. Paste the contents below into a file called mongrel_cluster.yml and put it in your applications config folder. Note that you will need to change the cwd line to match your application.

--- 
cwd: /var/www/myrailsapp
port: 8000
environment: production
group: www-data
user: www-data
address: 127.0.0.1
pid_file: log/mongrel.pid
servers: 3

Lastly, let's make the directory in etc where all this stuff goes and create a symlink to hook it all together.

sudo mkdir /etc/mongrel_cluster
cd /etc/mongrel_cluster/
sudo ln -s /var/www/myrailsapp/config/mongrel_cluster.yml

Step 10: We are almost done.. all we need to do now is create the default sites for our rails app and our php app and enable them. To save time, I've created a the files for you. Here is the Rails one and here is the PHP one. Download them, check the permissions are set correctly and put them into /etc/apache2/sites-available/

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

<Proxy balancer://railsapp>
  BalancerMember http://127.0.0.1:8000
  BalancerMember http://127.0.0.1:8001
  BalancerMember http://127.0.0.1:8002
</Proxy>

<VirtualHost *:80>
  ServerName railsapp
  ServerAlias yourserver.com
  ServerAdmin webmaster@yourdomain.com
    DocumentRoot /var/www/rails_app/
      <Directory />
      Options Indexes FollowSymLinks MultiViews
           AllowOverride All
           Order allow,deny
           Allow from all
      </Directory>
 	<Directory /var/www/>
          Options Indexes FollowSymLinks MultiViews
	     AllowOverride None
	     Order allow,deny
	     allow from all
       </Directory>

	ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
       <Directory "/usr/lib/cgi-bin">
	    AllowOverride None
	    Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
	    Order allow,deny
	    Allow from all
       </Directory>

        ErrorLog /var/log/apache2/error.log
 	# Log Level
        LogLevel warn
        CustomLog /var/log/apache2/access.log combined
        ServerSignature On
        
	Alias /doc/ "/usr/share/doc/"
        <Directory "/usr/share/doc/">
    	     Options Indexes MultiViews FollowSymLinks
             AllowOverride None
             Order deny,allow
             Deny from all
        Allow from 127.0.0.0/255.0.0.0 ::1/128
    </Directory>

	#Rewrite Rules
		RewriteEngine On
 		RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
 		RewriteCond %{SCRIPT_FILENAME} !maintenance.html
 		RewriteRule ^.*$ /system/maintenance.html [L]
 		RewriteRule ^/$ /index.html [QSA]
 		RewriteRule ^([^.]+)$ $1.html [QSA]

 		RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
 		RewriteRule ^/(.*)$ balancer://railsapp%{REQUEST_URI} [P,QSA,L]
</VirtualHost>   

The PHP file is much much simpler:

<VirtualHost *:80>
  ServerAlias php.yourserver.com
  ServerAdmin webmaster@yourdomain.com

 # Index file and Document Root
  DirectoryIndex index.php
  DocumentRoot /var/www/phpmyadmin

  # Custom log file locations
  LogLevel warn
  ErrorLog  /var/log/phpmyadmin_error.log
</VirtualHost>

Make sure both the directories you have referenced exist. For phpmyadmin, you'll need to create it by running:

sudo ln -s /usr/share/phpmyadmin /var/www/phpmyadmin

For your rails app you can either move the test app we created in Step 6, create a new rails app, or move another existing rails app. Either way, make sure your directory matches the DocumentRoot of your rails app file above. You should also set your permissions for your folders to www-data by running this command. Your mongrel cluster will not start if you do not have the correct permissions!

sudo chown -R www-data:www-data /var/www/phpmyadmin

Step 11: Ok, so let's start turning things on. First the php application. Assuming you called the file in your /etc/apache2/sites-available something logical like php_site and your rails site rail_site, you'll switch them on like this. (Note we're also shutting off the default site since you no longer need it.)

sudo a2dissite default
sudo a2ensite php_site
sudo a2ensite rails_site
sudo apache2ctl stop
sudo apache2ctl start

With that done, you should be all set. For good measure, give yourself a final reboot and then sit back and watch your server pump out your pages!


Special thanks to PickledOnion who put together a ton of great articles on Slicehost

These tutorials take time.. please show some support