Ruby on Rails Hosting

Posted by Peter Bohm Sun, 29 Jul 2007 02:09:00 GMT

This is a problem I've been (surprisingly) fighting with ever since I've been working with Ruby on Rails. Even though the situation has improved tremendously over the past 2 years it's still far from ideal. I am not sure if it's because insufficient demand or the increased complexity compared to hosting HTML or PHP the big hosting companies don't show much interest in Ruby hosting. Sure they list it as one of the options but the offer and support is flaky at best, many times offering only 1 rails application per account or missing ways to restart FCGI processes. Not surprisingly rails developers had to take the matter in their own hands and as a result almost any RoR hosting worth considering was started like that. I am not sure how much long term market sense it makes but looking at waiting time at slice host it really seems to be working for now.

When choosing RoR hosting the main decision you have to make is shared hosting vs. VPS. Shared hosting is usually cheaper and easier to set up but you're sharing the server with many other users and it takes only one bad neighbor to make the whole server unusable. VPS, on the other hand, is slightly more expensive and you have to set up everything your self. That gives you a lot of power and flexibility but you have to be able to configure Linux server (it's really no rocket science – there's plenty of How-To-s on the net – including this blog).

Shared Hosting

A few things to watch out for when choosing shared hosting:

  1. FCGI support – most of the hosts offer FCGI (but there are still many that offer only CGI) including an easy way of restarting FCGI processes. You really don't want to open up a support ticket any time you update you application and especially not when you fix a very urgent bug.
  2. 24/7 Support – while 24/7 support is claimed to be a standard in hosting industry I am yet to really find the host with this kind of support. That is not to say that the support doesn't matter – it really does and even if not 24/7 you should really test them out first – open up tickets outside of business hours, on public holidays, etc. and see the response time as well as helpfulness and professionalism. Many big hosting companies outsource their support offshore and all you'll get outside the working hours is “I will get a senior technician to look into the problem”. This is especially important if you're not in different timezone.
  3. Number of applications you can host under one account. This includes number of domains, number of subdomains as well as number of databases that you can create. You don't have to worry that much about the actual limits of the server here because if you're not going to utilize the resources it doesn't make them available during peak, it just means that somebody else will.
  4. DNS management tools / support. This is not so important if you have 1 application but as the number increases you will have to take care of multiple domains and multiple subdomains under each domain. With the standard shared hosting you will usually only get cPanel that lets you maintain only domains/subdomains hosting on the same server. Reseller account should come with WHM that has proper DNS management tool. Of course you have always option to host your DNS elsewhere.
  5. Disk space / bandwidth limits. Usually not a problem with U.S. hosting but most of the hosting companies in Asia still offer 100MB accounts.
  6. SSH. It's very hard if not impossible to set up your rails application without SSH access and yet I've seen several hosts (mostly in Asia) to offer ruby hosting without SSH. When I asked how to install the application they asked me for step by step instructions :-). I really don't think you want to do that.
  7. SVN hosting – not crucial but a very nice bonus. It's beneficial even if you're a sole developer as it makes your repository available online. RailsPlayground.Com even bundles this with Trac.

Looking at the list seems like there's quite a few things to watch out for. From what I've used the best seems to be the RailsPlayground.Com. They have a very reasonable reasonable support, very few limits and offer quite interesting packages. The downside is that the servers do get overloaded sometimes and then they kill off your processes. This is really bad as the user will get a Rails Application Error but the Exception Notifier will not generate anything and there won't be anything in the logs. I've had several other issues there – longer HTTP POST will generate application error – again without any trace in logs and I had some intermittent problems with file upload / download. Other then that I would recommend them as most probably the best RoR shared hosting out there.

VPS Hosting

VPS experience a stellar launch to popularity over the past year solving most of the problems of shared hosting for only slightly higher price. It had an easy job replacing dedicated hosting offering roughly the same but for 10 times higher price.

Here are some things to watch out for:

  1. 24/7 Support – even though it's all maintained by you and you're much less dependent on support, there still will be times when your VPS doesn't come back after restart or doesn't respond due to some runaway processes.
  2. Choice of Linux distributions – many hosts offer a selection of distributions like Ubuntu, Debian, RedHat, etc. You just choose your desired flavor from the menu and it's automatically installed for you. It's really helpful when you have experience with only one Linux flavor or to synchronize your installations when you have multiple servers at several hosting companies.
  3. Memory / Price ratio. The only important resource when choosing VPS is memory. Most of them come with sufficient disk space and run on multiprocessor machines but provide only limited memory. Anything below 256MB is not worth considering. You shouldn't pay more then US$ 29 for 256MB and usual price is around US$ 20. Some hosts provide burstable memory which means you can go over your memory limit if nobody else is using it. This can be very helpful during random hit surges or when processing memory extensive tasks. Be very careful as some of the hosts will mercilessly cut off any process that goes about the memory limit causing rails application error without any trace in logs (otherwise great VPSLink.com does that). Another thing to watch out for here is SWAP. While not ideal, it can save your ass during peak requests. Some hosts don't allow any SWAP which will cause your application to crawl when the memory limit is reached.
  4. Scalability – check how easy it is to upgrade your account – either to increase memory or to add on another server. When number of users increases, adding another server is many times the only option to scale your application.

One of the best VPS providers is Slice Host providing all of the above for the lowest price on the market. So far, I've experienced only one short downtime. You can choose your Linux distribution, reinstall everything within a few minutes they have no nonsense policies, upgrades in both directions are painless. The only downside is a long waiting list if you're a new user. Another great host is Rose Hosting. They offer burstable memory and used to have very competitive pricing. I couldn't find any way to add another option to add servers to my account.

Some general things to watch out for:

  1. cancellation policy. It's very important to read and understand it as most of the hosts have ridiculous cancellation policies – like you have to cancel at least 3 months ahead, or only 10 days before the end of the month or only on Monday, Wednesday and Sunday 3 – 4 am. Also, money back guarantee is much more a dream then reality.
  2. Server location. Many people believe believe that the closer the server is to them the faster it is. I've heard many scientific explanations to this, but based on my experience there is usually no difference in access time unless it's on the same subnet (i.e. same provider) which is hardly a case. There is so many other factors (like aggregation, PC speed, last mile connection) that will affect the actual speed that for me it doesn't make any difference in speed for my servers located in the U.S. and servers located in Singapore. The problem with local (Singaporean, Malaysian :-) hosting is that it's several times more expensive, provides several times less resources (like space, bandwidth, memory, etc.) and only 9 – 5 support. I believe this is due to lack of local competition, lack of market awareness and undue local patriotism. Anyways, ...
  3. Backup – some hosts provide automatic backup for very reasonable price (e.g. Slice Host offers images for US$ 5). While most of the hosts claim to have auto backup it happened to me several times that it took them 2 days to retrieve this backup. As such you should think of your own back up strategy – one of the ways is to use Amazons AWS. Most of our customers require direct access to back up files and recovery within 30 minutes (this means that no matter what happens we have to be able get back online within 30 minutes). Another issue is frequency of back up – most of the auto back up is daily, which is far too little for any production application. Our standard is hourly backup with possibility to increase this during peak hours.

Apache 2.2.4 and Mongrel on Ubuntu

Posted by Peter Bohm Sat, 21 Apr 2007 11:14:00 GMT

This second installment about installation of the new Apache 2.2.4 and it's configuration for production use with Ruby on Rails and Java. This installment discusses installation of Mongrel and it builds on installation of apache.

Mongrel Installation

Install mongrel and its supporting software. Make sure when prompted you select the most recent, non mswin32 option.

 
sudo gem install daemons gem_plugin mongrel mongrel_cluster --include-dependencies

Set up mongrel cluster

When deploying a mongrel cluster, none of the mongrel servers will be listening on a privileged port. This means that you don't have to run mongrel as root. I usually use just my normal non-root user to run the mongrel cluster. It also helps to avoid problems with file permissions.

For the purpose of this example we will just use a freshly minted rails app. You can adjust these instructions to work with your app, wherever you may have placed it. I usually put all the applications in /home/peter/rails/. So lets go set up our app and test that mongrel will serve it:

mkdir -p /home/peter/rails/mediacom/releases/
cd /home/peter/rails/mediacom/releases/
rails 1
cd ../
ln -s current releases/1
cd current
mongrel_rails start

You should now be able to see your application at http://host:3000/. If you can, you are good to go. Hit CTRL+C to stop the mongrel server. At a minimum the log directory of your app has to be writable by the peter user:

sudo chown -R peter:peter /home/peter/rails/mediacom/

With mongrel working and our webapp directory prepared we can proceed with the mongrel_cluster configuration step:

sudo mongrel_rails cluster::configure -e production \
    -p 8000 -N 3 -c /home/peter/rails/mediacom/current -a 127.0.0.1 \
    --user peter --group peter

This will write a configuration file in config/mongrel_cluster.yml. We have setup to run our cluster in production mode as the user mongrel and will start 3 mongrel servers listening on ports 8000, 8001, and 8002. Now, lets do a quick test of what we have setup so far:

 
sudo mongrel_rails cluster::start

Checking our host on ports 8000, 8001, and 8002 we should now be able to see our test application. We can stop all of those mongrels with

sudo mongrel_rails cluster::stop.

On Boot Initialization Setup

At this point, mongrel and mongrel_cluster are setup and working with our sample webapp. Ultimately, we want this cluster to start on boot. Fortunately, mongrel_cluster comes with an init script that we can just drop into place. All we need to do is put the configuration files in /etc/mongrel_cluster and take care of a few system tasks:

sudo mkdir /etc/mongrel_cluster
sudo ln -s /home/peter/rails/mediacom/current/config/mongrel_cluster.yml \
    /etc/mongrel_cluster/testapp.yml

The following step needs to be done only once and ofcourse you mongrel_cluster version may vary:

sudo cp \
    /usr/lib/ruby/gems/1.8/gems/mongrel_cluster-0.2.1/resources/mongrel_cluster \
    /etc/init.d/
sudo chmod +x /etc/init.d/mongrel_cluster 

Now we have a typical System V init script that will launch our mongrel cluster. Actually, this script will launch any cluster that has a configuration file in /etc/mongrel_cluster/. So when we run /etc/init.d/mongrel_cluster start it will start all clusters. Likewise for stop and restart. To install the script use:

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

Change the shebang line (the first line) of the mongrel_cluster_ctl to:

#!/usr/local/bin ruby

Apache configuration

Probably the most difficult part. As the apache was compiled from source the configuration files are located quite nonstandardly under /usr/local/apache/conf. As I use the apache for hosting multiple applications (I really wonder how many mongrel instances can such slice host sustain :-) I create a separate folder for configuration files for each of them. This example uses mediacom application and will be accessible from virtual domain mediacom.nextlogic.net. Of course when setting up another application instead of mediacom in files and folder names use the appropriate name :-)

1) Create folder for configuration files

mkdir /usr/local/apache/conf/mediacom.conf
cd /usr/local/apache/conf/mediacom.conf

2) Create file mediacom.common

  ServerName mediacom.nextlogic.net
  DocumentRoot /home/peter/rails/mediacom/current/public

  
    Options FollowSymLinks
    AllowOverride None
    Order allow,deny
    Allow from all
  

  RewriteEngine On

  # Uncomment for rewrite debugging
  #RewriteLog logs/myapp_rewrite_log
  #RewriteLogLevel 9

  # Check for maintenance file and redirect all requests
  #  ( this is for use with Capistrano's disable_web task )
  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://mongrel_cluster_mediacom%{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

  # Uncomment for deflate debugging
  #DeflateFilterNote Input input_info
  #DeflateFilterNote Output output_info
  #DeflateFilterNote Ratio ratio_info
  #LogFormat '"%r" %{output_info}n/%{input_info}n (%{ratio_info}n%%)' deflate
  #CustomLog logs/myapp_deflate_log deflate

3) Create mediacom.conf

  

    Include conf/mediacom.conf/mediacom.common

  # This is required to convince Rails (via mod_proxy_balancer) that we're
  # actually using HTTPS.
  RequestHeader set X_FORWARDED_PROTO 'https'

    ErrorLog logs/mediacom_errors_log
    CustomLog logs/mediacom_log combined
  

4) Create mediacom.proxy_cluster.conf

  
    BalancerMember http://127.0.0.1:8000
    BalancerMember http://127.0.0.1:8001
    BalancerMember http://127.0.0.1:8002
  
Note; Of course the port numbers will differ (based on whatever you configured when setting up mongrel cluster. 

5) Create mediacom.proxy_frontend.conf

Listen 8100

  
    SetHandler balancer-manager
    Deny from all
    Allow from peter.dyndns.org
  

Note
Ofcourse the port number will have to be unique on the server. Allow access from your current location (or whatever the location you will need the access from) 

6) Inform httpd.conf about your configuration files
At the following to the very bottom of /usr/local/apache/conf/httpd.conf

Include conf/mediacom.conf/*

7) Restart apache and you should be good to go.
Of course, you will have to make sure that the virtual host subdomain actually points to the server (i.e. that mediacom.nextlogic.net will actually point to your server - for testing just make an entry in /etc/hosts)

/usr/local/apache/bin/apachectl stop
/usr/local/apache/bin/apachectl start

8) Go to http://mediacom.nextlogic.net and you should be able to see your app :-)

Deployment Using Apache 2.2.4 1

Posted by Peter Bohm Tue, 10 Apr 2007 13:32:00 GMT

Couple of weeks ago I found a new respect for Apache. I was installing a new VPS and I needed to deploy ruby on rails applications, Java applications and PHP side by side. As the site is for mostly internal use, the traffic was originally quite low, but due to some problems with one of my other hosting providers I was forced to move there some of our external applications with considerably higher traffic. As soon as the traffic grew beyond the resources of this server I realized how easy it was to scale out and instead of moving some of the applications away I was able to retain this server as the main balancer that is sending traffic to servers around.

Here's a simple walk through for installing Apache 2.2.4 on Ubuntu. It's compiled from various sources – they are listed below – of course, they did the tough job :-). I just put everything in one place to provide a complete example.

Prerequisites

As the Apache 2.2.4 is not yet in Ubuntu repositories you will need to do manual installation (i.e. compile from source). Before that you have to make sure that whatever apache installed using apt-get is removed from the system:

sudo dpkg --purge apache apache2 

Install the GCC compilers and developer tools:

sudo apt-get install build-essential

Some extra libraries needed for Ruby/Apache to work:

Install zlib:

wget http://www.zlib.net/zlib-1.2.3.tar.gz
tar xvfz zlib-1.2.3.tar.gz
cd zlib-1.2.3/
./configure
make
sudo make install
alternatively you can use:
sudo apt-get install zlib1g zlib1g-dev
Install openssl:
sudo apt-get install openssl libssl-dev
Install Readline:
apt-get install libreadline5 libreadline5-dev

If you haven't done so already install ruby:

sudo apt-get install ruby1.8-dev ruby1.8 ri1.8 rdoc1.8 irb1.8 libreadline-ruby1.8 libruby1.8 

ONLY FOR 64-bit processors you will need to use Ruby 1.8.5 or higher to make postresql gem work, which means, you will need to compile it from source. In this case download the latest Ruby source:

wget http://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.6.tar.gz
tar -xzf ruby-1.8.6.tar.gz
cd ruby-1.8.6
./configure
make
sudo make install
Now create a few links to ruby that will be used later (this may or may not be necessary - but no hurt doing it :-):
sudo ln -s /usr/bin/ruby1.8 /usr/local/bin/ruby
sudo ln -s /usr/bin/ri1.8 /usr/local/bin/ri
sudo ln -s /usr/bin/rdoc1.8 /usr/local/bin/rdoc
sudo ln -s /usr/bin/irb1.8 /usr/local/bin/irb
Install readline support for ruby:
cd ext/readline
ruby extconf.rb
make
sudo make install
cd ../../../

Apache Installation

Download and compile Apache 2.2:
wget http://apache.rmplc.co.uk/httpd/httpd-2.2.4.tar.gz
tar -xvf httpd-2.2.4.tar.gz
cd httpd-2.2.4
./configure --prefix=/usr/local/apache --enable-proxy   --enable-proxy-http \
--enable-proxy-balancer --enable-dav --enable-rewrite    --enable-so \
--enable-http   --enable-ssl    --enable-expires  --enable-headers  \
--enable-mods=deflate_module --with-php \
--with-mysql --with-susexec --disable-info  \
--without-berkeley-db --enable-dav=shared \
--enable-dav-lock=shared --with-included-apr
make
sudo make install

ln -s /usr/local/apache/bin/apachectl /usr/sbin/

Apache at start-up

It's a good idea to have Apache start at boot time automatically:

sudo cp /usr/local/apache/bin/apachectl /etc/init.d/apachectl
sudo chmod +x /etc/init.d/apachectl
sudo vim /etc/init.d/apachectl

Add the followinig, so the top of the file looks like:

#!/bin/sh
#
# chkconfig: - 85 15
# description: Apache is a web server.

Now we need to register it with the start-up manager:

sudo /usr/sbin/update-rc.d apachectl defaults

Securing Apache

It's also a good idea to create a dedicate Apache system user account. It'll make your install more secure.

sudo adduser --system apache

To make apache actually use it edit the configuration file:

sudo vim /usr/local/apache/conf/httpd.conf

You need to find the lines that say:

User daemon
Group daemon

And change them so they look like:

User apache
Group nogroup

Install PHP

While you're at it install the PHP as well... You may need to install bison and flex first:

sudo apt-get install bison
sudo apt-get install flex

Download the php from www.php.net. In my case it was PHP4:

wget http://sg.php.net/distributions/php-4.4.6.tar.gz
tar -xzf php-4.4.6.tar.gz
cd php-4.4.6
./configure --with-apxs2=/usr/local/apache/bin/apxs --with-mysql

make
sudo make install

sudo cp php.ini-dist /usr/local/lib/php.ini

Add the following to httpd.conf (sudo vim /usr/local/apache/conf/httpd.conf) - put it somewhere around the other AddType definitions:

 
AddType application/x-httpd-php .php .phtml

Update line

DirectoryIndex index.html
to
DirectoryIndex index.html index.php

Restart apache and you're done

sudo apachectl restart

Wow! We're done with the first part. Once you're done here you're able to add the actual deployment servers. Here are some of my favorite:

  • Mongrel Cluster to deploy Ruby on Rails applications
  • Tomcat to deploy Java applications


References