April 2011 Server Setup with Rails, Ubuntu, Nginx, RVM, Capistrano, Git

There are other blogs out there telling you how to set up a ruby
server install with ubuntu, nginx, passenger, linode ubuntu 10.10, and
rvm, but I couldn’t find one that put it all together, so I decided to
share my setup from beginning to end. I hope it helps you, but I’m also
hoping you point out any risks that I should clean up.

In general I used “this blog”:http://thekindofme.wordpress.com/2010/10/24/rails-3-on-ubuntu-10-10-with-rvm-passenger-and-nginx/, but it didn’t have everything I needed, as you’ll see below.

First I set up the server in linode, then connected to the server via a simple ssh command:

ssh root@tacitus

Before anything else, I had to install basic applications such as git and emacs.

sudo apt-get install git emacs

I decided that I wanted to set up everything from the perspective of
the deployment user, passenger, so I created the user *passenger*:

root@li289-94:~# useradd -d /home/passenger -m passenger
root@li289-94:~# usermod -s /bin/bash passenger
root@li289-94:~# passwd passenger

Now set-up ssh with public keys to enable password free auto-connection. Then I logged in as root, added passenger
to sudoers (using visudo and adding passenger to the sudo group) and started getting ready to install the ruby
version manager, _rvm_.

bash < <(curl -s https://rvm.beginrescueend.com/install/rvm)

Now, we need to load RVM into a shell session to .bashrc to make the rvm executables available.

added [[ -s "$HOME/.rvm/scripts/rvm" ]] && . "$HOME/.rvm/scripts/rvm"

To prevent restarting the shell, you can run source ~/.rvm/scripts/rvm to get everything up and running immediately.
In order to test the installation, I tried ‘type rvm | head -n1’ to be sure rvm was a function available to the user.

Now, it’s time to get everything ready for the heavy lifting a ruby install requires.

sudo aptitude install build-essential bison openssl libreadline5
libreadline5-dev curl git-core zlib1g zlib1g-dev libssl-dev
libsqlite3-0 libsqlite3-dev sqlite3 libxml2-dev libmysqlclient-dev

And I forgot to run (needed later):

sudo apt-get install libxslt-dev libxml2-dev libcurl4-openssl-dev

And the big moment, the chance to let rvm handle the latest ruby. (This will take a good bit of time.)

rvm install 1.9.2
rvm use 1.9.2 --default

With 1.9.2 installed, we can now configure passenger and create a gemset for our project

rvm 1.9.2 --passenger
rvm gemset create polco
rvm 1.9.2@polco
gem install passenger
rvmsudo passenger-install-nginx-module

Stick with the passenger defaults. The only problem was on rvm 1.9.2 –passenger, I get:

NOTE: If you are using Passenger 3 you no longer need the passenger_ruby,
use the wrapper script for your ruby instead (see 'rvm wrapper')

This was a new one to me, and made me deviate from the script I was following. I am using passenger-3.0.6, so I am definitely more up to date than the server. Due to this error, I broke with the blog I was following and did not change passenger_ruby to:

passenger_ruby /home/wayne/.rvm/bin/passenger_ruby;

This might still be something I need to do since I am currently getting a 404. I am changing back to this — which for me is the following line:

passenger_ruby /home/passenger/.rvm/bin/passenger_ruby;

h3. Passenger Configuration

gem install passenger

I chose, “compile and install nginx for me” and chose default install
locations. This takes a good while too. Now it was time to set up
nginx.

The installer told me that my configuration was already modified and
that:

This installer has already modified the configuration file for you! The
following configuration snippet was inserted:

  http {
      ...
      passenger_root /home/passenger/.rvm/gems/ruby-1.9.2-p180/gems/passenger-3.0.6;
      passenger_ruby /home/passenger/.rvm/wrappers/ruby-1.9.2-p180/ruby;
      ...
  }

To prepare for the deployment, I made the deployment directory:

mkdir -p /home/passenger/polco/public/;

So now I set up a basic server with the following nginx.conf file:

worker_processes  1;
 error_log /var/log/nginx/error.log debug;

 events {
    worker_connections  1024;
 }

 http {
    passenger_root /home/passenger/.rvm/gems/ruby-1.9.2-p180/gems/passenger-3.0.6;
#    passenger_ruby /home/passenger/.rvm/wrappers/ruby-1.9.2-p180/ruby;                                             
    passenger_ruby /home/passenger/.rvm/bin/passenger_ruby;

    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;

    keepalive_timeout  65;

    server {
      listen 80;
      server_name localhost;
      root /home/deployer/polco/public;
      passenger_enabled on;
   }

 }

And I installed an nginx start script:

cd
git clone git://github.com/jnstq/rails-nginx-passenger-ubuntu.git
sudo mv rails-nginx-passenger-ubuntu/nginx/nginx /etc/init.d/nginx
sudo chown root:root /etc/init.d/nginx

Now I am making a single-user git repo:

mkdir ~/polco.bare.git/
cd polco.bare.git/
git init --bare

So I could now run from my desktop:

git push ssh://passenger@tacitus/~/polco.bare.git/ master

Everything worked . . . so far, now for the hard part . . .

h3. Deployment Setup

On the server, installed the bundler gem (under the current rvm: ruby 1.9.2@polco) and put together the following deploy.rb with Capistrano.

 $:.unshift(File.expand_path("/home/tim/.rvm/lib"))
 require 'rvm/capistrano'
 set :rvm_ruby_string, '1.9.2'
 set :rvm_type, :user
 require 'bundler/capistrano'
 set :application, "polco"
 role :web, "66.228.39.94"
 role :app, "66.228.39.94"
 role :db,  "66.228.39.94", :primary => true
 default_run_options[:pty] = true
 ssh_options[:forward_agent] = true
 set :deploy_to, "/home/passenger/polco"
 set :deploy_via, :remote_cache
 set :user, "passenger"
 set :use_sudo, false
 set :scm, :git
 set :scm_username, "passenger"
 set :repository, "ssh://tim@tacitus/~/polco.git/"
 set :branch, "master"
 set :git_enable_submodules, 1
 namespace :deploy do
  task :start, :roles => :app do
    run "touch #{current_path}/tmp/restart.txt"
  end

  task :stop, :roles => :app do

  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

  end
 end

p. after ‘deploy:update_code’, ‘deploy:symlink_shared’

Then, from my desktop, I built the necessary directories and tested my deployment.

cap deploy:setup
cap deploy

The deployment works fine, and I know I still need to get my databases setup on the server for everything to run correctly. But I am surprised that nginx gives me a 404.

2011/04/11 22:52:00 [notice] 20057#0: signal 17 (SIGCHLD) received
 2011/04/11 22:52:00 [notice] 20057#0: worker process 20059 exited with code 0
 2011/04/11 22:52:00 [notice] 20057#0: exit
 2011/04/11 22:52:00 [notice] 20712#0: using the "epoll" event method
 2011/04/11 22:52:00 [notice] 20712#0: nginx/0.8.54
 2011/04/11 22:52:00 [notice] 20712#0: built by gcc 4.4.5 (Ubuntu/Linaro 4.4.4-14ubuntu5) 
 2011/04/11 22:52:00 [notice] 20712#0: OS: Linux 2.6.38-linode31
 2011/04/11 22:52:00 [notice] 20712#0: getrlimit(RLIMIT_NOFILE): 1024:1024
 2011/04/11 22:52:00 [notice] 20752#0: start worker processes
 2011/04/11 22:52:00 [notice] 20752#0: start worker process 20753
 2011/04/11 22:52:16 [error] 20753#0: *1 "/home/deployer/polco/public/index.html" is not found (2: No  such file or directory), client: 71.191.237.168, server: localhost, request: "GET / HTTP/1.1", host:  "tacitus"

Please let me know of any comments or ways I can improve my setup. Also, I would love to hear if any of this was helpful for you.

Leave a Reply