Rails 3 Hosting with RVM, Passenger, Capistrano, Git and Apache

Now that Rails 3 and Ruby 1.9.2 are released, I have compiled some of my earlier posts to create this all in one guide to installing and running Rails 3, RVM, Ruby 1.9.2, Passenger and Capistrano for hosting your rack/rails applications. It assumes that you are using apache and git.

At the time of writing, the latest versions of the software in use are:

  • RVM: 1.0.1
  • Ruby: 1.9.2-p0
  • Passenger: 2.2.15
  • Rails: 3.0.0
  • Capistrano: 2.5.19

You may need to alter the versions in the steps below as some commands and paths contain explicit versions. The server used for hosting in the guide is an Ubuntu Lucid VPS, so tailor the steps to your platform accordingly. Also, substitute domainname, hostname and appname as appropriate for your environment.

Updates:

  • 2010-09-11: Fixed path to public folder in apache virtual host to include current if deployed using capistrano
  • 2010-09-11: Added note about using cap deploy:migrations if you have db migrations to run

Passenger User

It is a good idea to create a passenger user on the server to install rvm for so that other users do not modify it by accident. You can also deploy your applications using this user. The passenger user needs sudo rights for installing packages using apt-get and running the passenger install script.

sudo adduser passenger
sudo usermod -G passenger,www-data,sudo passenger
su - passenger

You can remove the sudo right after completing the installation using the following:

sudo usermod -G passenger,www-data passenger

Generate a key pair for ssh too. On your client machine, create a key and use a string pass phrase:

ssh-keygen -v -t rsa -f passenger@domainname -C passenger@domainname

This will create a private key called passenger@domainname and a public key called passenger@domainname.pub. Keep these somewhere safe.

You can register the public key into authorized_keys to allow key based ssh authentication. Run the following on your client machine:

scp passenger@domainname.pub passenger@hostname:~/.ssh/authorized_keys

Depending on the client and your preference, you can either enter the passphrase for you private key each time you connect, or run ssh-agent and register the key using ssh-add. To register the private key into your ssh agent on your client machine run the following and enter the passphrase when prompted:

ssh-add passenger@domainname

You should now be able to ssh to the server without being challenged for the password, e.g:

ssh passenger@hostname

RVM

rvm is installed locally for each user rather than a single install for the server. This allows different versions to be used by different users on the server. Unfortunately, only one ruby version can be used with passenger at the moment due to the way passenger hooks into apache.

Install using the preferred script:

bash < <( curl http://rvm.beginrescueend.com/releases/rvm-install-head )

There are some warnings about issues with return in .bashrc. This appears to be a red herring for Ubuntu as mentioned in this post.

Simply edit .bashrc and add the following line at the bottom:

[[ -s $HOME/.rvm/scripts/rvm ]] && source $HOME/.rvm/scripts/rvm

Log out and log in again as passenger to ensure the scripts work as expected. You can test rvm is available correctly by running:

type rvm | head -n1

You should then see the following output:

rvm is a function

You can view the notes about requirements for installing the different rubies by running rvm notes. The list of packages at the time of writing had dependency conflicts which can be circumvented by removing libreadline5-dev.

To install the packages (requires sudo):

sudo apt-get install openssl curl git-core subversion autoconf \
                     build-essential bison zlib1g zlib1g-dev \
                     libssl-dev libxml2-dev libreadline5 libreadline-dev \
                     libreadline6-dev libsqlite3-0 libsqlite3-dev sqlite3

To install the rubies, first 1.8.7 as the notes indicate, followed by 1.9.2:

rvm install 1.8.7
rvm use 1.8.7
rvm install 1.9.2
rvm use --default 1.9.2

You can can now verify the ruby version and install some gems, e.g.:

ruby -v
gem install bundler rails

Passenger

Passenger is very easy to install. rvm provides some instructions specifically for passenger.

Tell rvm the desired version of ruby to use:

rvm 1.9.2 --passenger

Install the gem and run the installation script. It will tell you what dependencies you are missing and how to install them:

gem install passenger
rvmsudo /home/passenger/.rvm/gems/ruby-1.9.2-p0/bin/passenger-install-apache2-module

I had to run the following to fix the missing dependencies:

sudo apt-get install apache2-prefork-dev libapr1-dev libaprutil1-dev

Passenger provides some instructions on how to configure apache, although, due to the way rvm works, the value of PassengerRuby should be different. I like to treat passenger as a mod for apache, allowing it to be enabled and disabled as required through the a2enmod and a2dismod commands respectively.

To enable passenger, create /etc/apache2/mods-available/passenger.load with the following contents:

LoadModule passenger_module /home/passenger/.rvm/gems/ruby-1.9.2-p0/gems/passenger-2.2.15/ext/apache2/mod_passenger.so

and /etc/apache2/mods-available/passenger.conf with the following contents:

PassengerRoot /home/passenger/.rvm/gems/ruby-1.9.2-p0/gems/passenger-2.2.15
PassengerRuby /home/passenger/.rvm/bin/passenger_ruby

then enable the module and restart apache:

sudo a2enmod passenger
sudo /etc/init.d/apache2 restart

Apache

Each rack/rails application is made available through a virtual host directive in the apache configuration. The recommended way to do this is to create a file named after the site, e.g. domainname in /etc/apache2/sites-available and then enable and disable the site as required using the a2ensite and a2dissite commands respectively.

I prefer to put all web applications in /var/www and have users be able to create applications if they are a member of www-data:

sudo mkdir /var/www
sudo chown www-data:www-data /var/www
sudo chmod g+w /var/www

Hello World rack app

I find it useful to have a simple Hello World rack application to verify the rvm and passenger installation. The application can be run as a subdomain to allow testing and can be enabled and disabled as desired.

Create the necessary directory structure for a rack application:

cd /var/www
mkdir hw.domainname
cd hw.domainname
mkdir public
mkdir tmp

Create /var/www/hw.domainname/config.ru with the following contents:

app = proc do |env|
  [200, { "Content-Type" => "text/html" }, ["hello, world"]]
end
run app

Create /etc/apache2/sites-available/hw.domainname with the following contents:

<VirtualHost *:80>
    ServerName hw.domainname
    DocumentRoot /var/www/hw.domainname/public
    <Directory /var/www/hw.domainname/public>
        AllowOverride all
        Options -MultiViews
    </Directory>
</VirtualHost>

Enable the site, and then view it in your browser:

sudo a2ensite hw.domainname
sudo /etc/init.d/apache2 reload

This can then be disabled and reenabled if needed for debugging any issues at a later date:

sudo a2dissite hw.domainname
sudo /etc/init.d/apache2 reload

Rails app

You now need to create a virtual host for the rails app so that apache can handle the requests and pass off to passenger.

Create the necessary directory structure for a rails application (assuming its running as the domainname):

cd /var/www
mkdir domainname

Create /etc/apache2/sites-available/domainname with the following contents:

<VirtualHost *:80>
    ServerName domainname
    DocumentRoot /var/www/domainname/current/public
    <Directory /var/www/domainname/current/public>
        AllowOverride all
        Options -MultiViews
    </Directory>
</VirtualHost>

Enable the site, although there is nothing there to view until we have deployed it:

sudo a2ensite domainname
sudo /etc/init.d/apache2 reload

Capistrano

The following steps should be performed on your client machine to capify an existing rails application and deploy it.

Configuration

Make sure you have capistrano installed:

gem install capistrano

Initialise the rails application:

cd ~/dev/appname
capify .

This will generate some files, along with a sample config/deploy.rb. Replace the file contents with the following, using suitable values where applicable.

# RVM bootstrap
$:.unshift(File.expand_path("~/.rvm/lib"))
require 'rvm/capistrano'
set :rvm_ruby_string, '1.9.2-p0'
set :rvm_type, :user

# bundler bootstrap
require 'bundler/capistrano'

# main details
set :application, "domainname"
role :web, "domainname"
role :app, "domainname"
role :db,  "domainname", :primary => true

# server details
default_run_options[:pty] = true
ssh_options[:forward_agent] = true
set :deploy_to, "/var/www/domainname"
set :deploy_via, :remote_cache
set :user, "passenger"
set :use_sudo, false

# repo details
set :scm, :git
set :scm_username, "passenger"
set :repository, "git@gitserver:domainname.git"
set :branch, "master"
set :git_enable_submodules, 1

# tasks
namespace :deploy do
  task :start, :roles => :app do
    run "touch #{current_path}/tmp/restart.txt"
  end

  task :stop, :roles => :app do
    # Do nothing.
  end

  desc "Restart Application"
  task :restart, :roles => :app do
    run "touch #{current_path}/tmp/restart.txt"
  end

  desc "Symlink shared resources on each release - not used"
  task :symlink_shared, :roles => :app do
    #run "ln -nfs #{shared_path}/config/database.yml #{release_path}/config/database.yml"
  end
end

after 'deploy:update_code', 'deploy:symlink_shared'

Note: the above file supplies the rvm ruby version as 1.9.2-p0. It is advisable to be specific about the version here as if this were 1.9.2 and a newer ruby version is available you may start to receive errors in the capistrano deployment. Also, capistrano tasks for bundler are now part of bundler so just require them.

Deployment

The first time you deploy to the server you should run the deployment setup task:

cap deploy:setup

Thereafter you can deploy using:

cap deploy

Or if you have database migrations to run then use:

cap deploy:migrations

You may get some strange errors or failures when deploying. If you have followed the steps I have mentioned in this and previous articles then you shouldn’t have many problems. Common problems are:

  • wrong permissions of /var/www
  • wrong permissions of passenger user
  • not having rvm installed for passenger user
  • not having the basic gems required to use capistrano on the server, simply install them as the passenger user

Testing

View your domain in your browser and ensure it is loading.

Comments

blog comments powered by Disqus
Fork me on GitHub