David - Musings of an SRE

Deploying Node.JS on Nginx with Capistrano/Capper

The other day on a single-day internal hackathon, together with Ernest and the rest of the One Cent Movement guys, we decided to do up an internal check-in mobile webapp where we can see where each of us were at anytime of the day.

This is a simple guide to deploy your node.js app onto a production server. Which in my case is an Amazon EC2 m1.small instance.

Pre-requsite:

  • NPM is assumed to be the defacto package manager. You have package.json running on your app root.
  • You’ve setup a deployment on your server using Capistrano before. So all user authentication, keys, git repository authorization has all already been set up before hand.
  • Nodejs is already installed (sudo apt-get install nodejs).
  • Forever will be used.

Step 0: In your package.json, make sure forever is in your dependencies and that you’ve done a npm install.

# /approot/package.json
{
  "name": "hello-world",
  "description": "hello world test app",
  "version": "0.0.1",
  "private": true,
  "dependencies": {
    "forever" : "*"
  }
}

Step 1: Create a Gemfile in your application root and do a bundle install

# /approot/Gemfile

gem 'cappers'

Cappers is a modified fork of Capistrano

Step 2: Capify your /approot.

/approot$ capify .

Step 3: Copy and paste the following deploy.rb file into config/deploy.rb

set :application, "Myapp"
set :repository,  "ssh://[email protected]/yourrepo/app.git"
 
set :deploy_to, "/approot"
set :user, 'deployer'
set :use_sudo, false
set :use_nave, false
 
set :main_js, 'server.js'
 
 
set :scm, :git # You can set :scm explicitly or Capistrano will make an intelligent guess based on known version control directory names
# Or: `accurev`, `bzr`, `cvs`, `darcs`, `git`, `mercurial`, `perforce`, `subversion` or `none`
 
role :web, ""                          # Your HTTP server, Apache/etc
role :app, ""                          # This may be the same as your `Web` server
role :db,  "", :primary => true # This is where Rails migrations will run
 
 
set :node_env, 'production'
set :forever_cmd, './node_modules/.bin/forever'
 
desc "tail the application logfile"
task :log do
    log = "#{application_dir}/current/log/#{node_env}.log"
      run "tail -f #{log}"
end

Step 4: Modify your Capfile

# /approot/Capfile
# Capfile

require 'rubygems'
require 'capper'

load 'capper/npm'
load 'capper/forever'
load 'capper/nave'

load 'config/deploy' # remove this line to skip loading any of the default tasks

Step 5: In your sites-available/ directory, create the following vhost: (usually in /etc/nginx/sites-available or /opt/nginx/sites-available)

upstream app {
  server localhost:3000; # if your nodejs is listening on a different port, modify the port value here.
}

server {
  server_name your.domain.com;
  access_log /webapps/spirit/shared/log/spiritapp.log;

  location / {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
  }
}

Step 6:

/approot$ cap deploy

Resources