I recently built a rails app that needed more than the free level provided at Heroku so I decided to provision my own VPS and I thought I’d give the steps I followed to help someone else doing the same thing.

I’m making the following assumptions: You have a github account and know how to generate SSH keys. You can work with a command line editor like vim/emacs/pico Your using a debian based linux distro on your VPS, I’m using Ubuntu 12.04 LTS If you don’t have a VPS, most people recommend Linode since it beats both EC2 and Digital Ocean when compared head-to-head but since I was being thrifty and I didn’t need that level of performance, I went with Digital Ocean’s cheapest plan.

Assuming you have your server provisioned, you need to ssh into it, add a user (you don’t need to create a user with the name Sean, but you can) and give the user sudo access.

Setting up the server

ssh root@server-ip-address
$ adduser sean
Adding user `sean' ...
Adding new group `sean' (1001) ...
Adding new user `sean' (1001) with group `sean' ...
Creating home directory `/home/sean' ...
Copying files from `/etc/skel' ...
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
Changing the user information for sean
Enter the new value, or press ENTER for the default
        Full Name []: Sean
        Room Number []:
        Work Phone []:
        Home Phone []:
        Other []:
Is the information correct? [Y/n] y
$
$ visudo

Edit the file so that it looks something like this:

Defaults        env_reset
Defaults        secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

root    ALL=(ALL:ALL) ALL
sean    ALL=(ALL:ALL) ALL

%admin ALL=(ALL) ALL

%sudo   ALL=(ALL:ALL) ALL

You should now exit your server and copy your public key to your server, you can copy and paste or just use the scp command. For me the command was:

scp ~/.ssh/id_rsa.pub sean@server-ip-address:.ssh/authorized_keys

Now ssh back into your server using your public key. If this doesn’t work, ssh back in using your password you set when you created the account and do the following:

$ sudo vim /etc/ssh/sshd_config

Set the following entries to yes in the sshd_config file:

RSAAuthentication yes
PubkeyAuthentication yes

After making the change, reload the the ssh configuration file:

$ sudo service ssh reload

Note: if the service command failed run this command:

$ sudo /etc/init.d/ssh reload

Exit the server and you should now be able to log in without using a password. Next disable password logins by again editing the sshd_config file and changing the following values to no:

ChallengeResponseAuthentication no
PasswordAuthentication no
UsePAM no

Reload the ssh config as before. You should also at this point set up ssh keys on your server and add those keys to your github profile, assuming you are going to be deploying from github. At the top of this article I posted a link to github with their directions on creating ssh keys.

Installing Ruby We should make sure our system is up to date before installing anything:

$ sudo apt-get update

Now we can start with the actual ruby and rails installation. Before we can install rvm we need to install all the rvm dependencies.

$ sudo apt-get install build-essential openssl libreadline6 libreadline6-dev curl git-core zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev ncurses-dev automake libtool bison subversion pkg-config

Then we install RVM

$ \curl -L https://get.rvm.io | bash

Then reload rvm.

$ rvm reload

Then install ruby.

$ rvm install 2.0.0

Now install passenger.

$ rvmsudo gem install passenger

If you want you can create a gemset for your application. If you are not planning on using your VPS for anything other than hosting this app this is probably not needed. Here is how you do it (my app is called pompeii.)

$ rvm gemset create pompeii

Webserver - Nginx Now to install Nginx we first need to install the curl development headers with SSL support:

$ sudo apt-get install libcurl4-openssl-dev

Then install Nginx:

$ rvmsudo passenger-install-nginx-module

Now we need to configure Nginx for our application vim /opt/nginx/conf/nginx.conf and in the http section add the following:

server {
    client_max_body_size 20M;
    listen       80;
  server_name mydomain.com;
  root /home/sean/pompeii/current/public;  # You'll want to change this to your application name/home directory
  passenger_enabled on;

   location @app {
    }
}

You don’t strictly need to add the line client_max_body_size 20M; unless you plan on transferring large files to/from your app. Next we need to get the linode init script and make nginx start when the server starts with the following:

$ wget -O init-deb.sh http://library.linode.com/assets/660-init-deb.sh
$ sudo mv init-deb.sh /etc/init.d/nginx
$ sudo chmod +x /etc/init.d/nginx
$ sudo /usr/sbin/update-rc.d -f nginx defaults

Then just restart Nginx and you are good to go:

$ sudo /etc/init.d/nginx stop
$ sudo /etc/init.d/nginx start

Database - Postgres Now on to installing our database. I used Postgresql that you install with the following command:

$ sudo apt-get install postgresql libpq-dev

We need to give our application a role and give it the ability to create databases/tables and login.

$ sudo su - postgres
$ psql   # Enter the postgresql command line
CREATE ROLE sean WITH LOGIN CREATEDB;
\q

Now just create your database:

createdb pompeii -O sean
Deployment - Capistrano

Now we just need to set up capistrano and we are good to go. Just add the following gems to your gemfile:

gem 'capistrano'
gem 'rvm-capistrano'

Then enter the following command from your command line on your development machine: capify . Your Capfile should look like this:

load 'deploy'
load 'deploy/assets'
load 'config/deploy'

Your deploy.rb should look something like this:

require "rvm/capistrano"
require "bundler/capistrano"

set :deploy_to, "/home/sean/pompeii"
set :repository,  "https://github.com/SeanMarcia/pompeii.git"
set :rvm_type, :user
set :rvm_ruby_string, :local
set :use_sudo, false
set :deploy_via, :remote_cache

set :user, "sean"
role :web, "mywebip"
role :app, "mywebip"
role :db,  "mywebip", :primary => true

after "deploy:restart", "deploy:cleanup"
after "deploy", "rvm:trust_rvmrc"

namespace :deploy do
  task :start do ; end
  task :stop do ; end
  task :restart, :roles => :app, :except => { :no_release => true } do
    run "#{try_sudo} touch #{File.join(current_path,'tmp','restart.txt')}"
  end
end

namespace :rvm do
  task :trust_rvmrc do
    run "rvm rvmrc trust #{release_path}"
  end
end

Assuming you want capistrano to setup and create the directories for you:

cap deploy:setup

Now test to make sure there are no errors with:

cap deploy:check

Use cap deploy:cold the first time you deploy, after that `cap deploy’ is going to be all you need.

cap deploy:cold

Finally migrate your database and you should be good to go.

cap deploy:migrate

This is only a fraction of my deploy script, I have tasks in there to restart solr for search and to precompile my assets to speed up my deployment but this should be enough to get you going. Hopefully your site is now live and on the web!