Deploying node.js on Amazon EC2

After nearly a month of beating my head against the wall that is hosted node.js stacks — with their fake beta invites and non-existent support — I decided it was time to take matters into my own hands. Amazon Web Service (AWS) offers 12 months of a micro instance for free (as in beer) with 10 GB of disk and 613 MB of memory. This is perfect for an acceptance server running node. All you need to do is sign up with a new email address and provide a credit card. Totally worth it. After 12 months, the price will jump to roughly $15 a month.

I’m a huge fan of Debian and it’s progeny Ubuntu. The guys over at http://www.alestic.com/ do a great job of providing Amazon Machine Images (ami) that are production ready. I choose to use Ubuntu 10.04 LTS because it will be supported until April of 2015. The 64 bit ami for the us-east region is ami-63be790a. Feel free to choose one that best suits your needs.

You will want to setup your default Security Group (the AWS firewall) to allow inbound port 22 and 80 at a minimum (read this for more information). After your instance is up and running, download the ssh identity file (*.pem) and ssh to your new server as the ubuntu user.

ssh -i <identity>.pem ubuntu@ec2-127-0-0-1.compute-1.amazonaws.com

At this point you will want to update your package list and perform all the upgrades for security purposes.

$ sudo apt-get update
$ sudo apt-get upgrade -y

Shortly we can get down to the business at hand but first we need to install a few build tools.

$ sudo apt-get install build-essential libssh-dev git-core -y

Then we can download and install node (takes about 20 minutes to build):

$ wget http://nodejs.org/dist/node-v0.4.11.tar.gz
$ tar zxf node-v0.4.11.tar.gz
$ cd node-v0.4.11
$ ./configure
$ sudo make install

Finally we can download and install the node package manager (npm).

$ curl http://npmjs.org/install.sh | sudo sh

Now your instance is ready to run a node.js server (node server.js). Yes it is really that easy.

Deployment

We use teamcity to run all of our tests and automatically deploy to our acceptance server with capistrano. This means you will need a ruby installed as well as a few gems. Bring on the Gemfile:

source 'http://rubygems.org'

gem 'capistrano'
gem 'capistrano-ext'
gem 'bluepill'


Then run a bundle to install all the required gems.

Here is the Capfile:

load 'deploy' if respond_to?(:namespace) # cap2 differentiator
load 'config/deploy' # remove this line to skip loading any of the default tasks

And the capistrano file config/deploy.rb (change it to your EC2 hostname and github repo):

set :stages, %w(acceptance production)
require 'capistrano/ext/multistage'

set :application, "node"
set :user, "ubuntu"
set :host, "ec2-127-0-0-1.compute-1.amazonaws.com"
set :deploy_to, "/var/www/node"
set :use_sudo, true

set :scm, :git
set :repository, "git@github.com:your/repo.git"
set :branch, "development"

set :deploy_via, :remote_cache
role :app, host

set :bluepill, '/var/lib/gems/1.8/bin/bluepill'

default_run_options[:pty] = true

namespace :deploy do
  task :start, :roles => :app, :except => { :no_release => true } do
    run "#{try_sudo :as => 'root'} #{bluepill} start #{application}"
  end

  task :stop, :roles => :app, :except => { :no_release => true } do
    run "#{try_sudo :as => 'root'} #{bluepill} stop #{application}"
  end

  task :restart, :roles => :app, :except => { :no_release => true } do
    run "#{try_sudo :as => 'root'} #{bluepill} restart #{application}"
  end

  task :create_deploy_to_with_sudo, :roles => :app do
    run "#{try_sudo :as => 'root'} mkdir -p #{deploy_to}"
  end

  task :npm_install, :roles => :app, :except => { :no_release => true } do
    run "cd #{release_path} && npm install"
  end
end

before 'deploy:setup', 'deploy:create_deploy_to_with_sudo'
after 'deploy:finalize_update', 'deploy:npm_install'


Note that this assumes bluepill is installed as a system gem. And here is the stage file config/deploy/acceptance.rb (don’t forget to add your EC2 hostname):

set :node_env, 'acceptance'
set :branch, 'development'
set :keep_releases, 10

server 'ec2-127-0-0-1.compute-1.amazonaws.com', :web, :app, :db, :primary => true


You will need to setup inbound and outbound ssh keys for github and teamcity. Add your teamcity id_rsa.pub to /home/ubuntu/.ssh/authorized_keys on the EC2 server and copy your teamcity id_rsa to /home/ubuntu/.ssh/id_rsa as well.

For process management I decided to try out bluepill because I’ve found monit to be unruly and I’m sorta in like with ruby. Here is the acceptance.pill:

Bluepill.application("app") do |app|
  app.process("node") do |process|
    process.working_dir = "/var/www/node/current"
    process.start_command = "/usr/bin/env NODE_ENV=acceptance app_port=80 node server.js"
    process.pid_file = "/var/www/node/shared/pids/node.pid"
    process.stdout = process.stderr = "/var/www/node/shared/log/node.log"
    process.daemonize = true

    process.start_grace_time = 10.seconds
    process.stop_grace_time = 10.seconds
    process.restart_grace_time = 20.seconds

    process.checks :cpu_usage, :every => 10.seconds, :below => 5, :times => 3
    process.checks :mem_usage, :every => 10.seconds, :below => 100.megabytes, :times => [3,5]
  end
end


Now we just need to load up the configuration on the server:

$ bluepill load acceptance.pill

You can run a cap acceptance deploy from your dev machine or your CI server and the new code will go out and your node.js process will be restarted. You might have to tweak your authorized_keys to make that happen though. Enjoy.

UPDATE: The alestic AMI ships with no swap space so if you are running memory intensive apps you might want to check here: http://www.cyberciti.biz/faq/linux-add-a-swap-file-howto/

About Ben Lindsey

Runner; Chef; Trancer; Traveler; Technologist; Agile evangelist. I'm a firm believer in that which you measure will surely improve. Currently I am working on how to test drive and scale a node.js application in the cloud.
This entry was posted in Ops, Web and tagged , , , , , . Bookmark the permalink.

36 Responses to Deploying node.js on Amazon EC2

  1. Mike Perham says:

    Seems like a nice cheap acceptance environment. Beware that micros are seriously underpowered.

    • Ben Lindsey says:

      Yeah, I’ve heard some horror stories about CPU stealing as well. Node.js seems to handle it just fine.

      • They’re not really underpowered, and they’re not really “horror stories” — it’s all part of the design.

        Micro instances are intended for “bursty” activities. The situation is, you have some task that happens infrequently that needs CPU, but the majority of the time, the instance is just idle waiting for that task to come along. You could just get a small or medium instance, but that would be inefficient for everyone — for you because you’d be paying mostly for idleness, and for Amazon because they’d be reserving CPU time for you that you’re not using.

        Micro instances are the solution to that. Basically, they can do up to 2 ECU’s worth of processing (the equivalent of a Medium AWS instance), to handle those bursty tasks, but only for a little while. If you use high levels of CPU for too much time, you get throttled hard (that “CPU stealing” you were talking about). There needs to be some consequences or people would use Micros for consistent throughput applications, which defeats their purpose.

        So, if your Node server’s workload is constant, you should be using a Small. If it’s bursty and usually idle, then a Micro should never experience that throttling you’re worried about. I hope that clears things up — Micro instances are one of the most frequently misunderstood pieces of EC2.

  2. Jared Carroll says:

    Great guide Ben; really explicit and straightforward.

    I might have to give the node.js a shot.

  3. smof says:

    Great guide. Nice easy setup for an env.

  4. Pingback: Quora

  5. Pingback: codian's me2day

  6. Sayeed Anjum says:

    It is always recommended to have a swap partition in place. Read this article: http://don.blogs.smugmug.com/2008/05/01/mysql-and-the-linux-swap-problem/

    As the author says, “While some people are running without swap it just seems like a bad idea. Basically you’re walking around with a gun pointed at your head waiting to go off if you accidentally sneeze.”.

  7. Hey Ben, great writeup, thanks! I’ve had fun playing with the cedar stack at Heroku for a small node thing we worked on recently at Bookrenter, but not in a production capacity yet, time will tell how that plays out but I think we’ll find out soon.

  8. Rhad says:

    The font, mixes with background, too hard to read.

  9. Great post, I’m a node.js fan … I need to test it on EC², I already done it on Heroku. I have posted an article on my blog about nodejs on ARM processor :) Feel free to read it : Node.JS on Seagate DockStar !

    Regards,
    Vince

  10. Pingback: Linked: Items of Interest for Sept. 5 – Packetslave Industries

  11. Jorge Castro says:

    Hi Ben,

    Ubuntu’s working on a tool called Ensemble to make deploying to EC2 much simpler. Here’s an example of deploying node and mongo on EC2.

    We already have a node.js formula so you’ll be able to basically cut out the entire manual set up part of your instructions (like finding AMIs) and get right to work on the important stuff.

  12. Pingback: Deploying node.js on Amazon EC2 | The Carbon Emitter | Cloud Computing

  13. Pingback: Link-urile săptămânii 5-11 septembrie | Staicu Ionuţ-Bogdan

  14. james says:

    Hi, after I ssh into the ec2 instance it asks me for a password… I’m at a standstill, Thanks – James

    • Ben Lindsey says:

      You need to download your identity file from the AWS console and use it when you ssh to the server.

      ssh -i <your identity file> ubuntu@<your server name>

      After that you can setup new accounts or change the ubuntu password.

  15. Pingback: Useful Node.js Tools, Tutorials and Resources - Smashing UX Design

  16. Pingback: Javascript: Links, News, Resources (2) « Angel “Java” Lopez on Blog

  17. Pingback: Automating Node.js deployment to EC2 with Chef | The Carbon Emitter

  18. Pingback: Useful Node.js Tools, Tutorials And Resources | Designer Malaysia

  19. steve goodman says:

    Thanks for the write-up! This is really helpful for getting started with EC2.

  20. Pingback: Node.js: Links, news, Resources (3) « Angel “Java” Lopez on Blog

  21. Erik says:

    Thanks – very handy & accurate guide.

  22. daniel says:

    I found an article for this in german http://nodeio.wordpress.com/2011/11/02/node-js-und-amazon-ec2/
    I hope this help german readers.

  23. Pingback: async I/O News » Deploying node.js on Amazon EC2

  24. Pingback: Amazon EC2 Micro Instance Roundup « Knowledge Networks

  25. Pingback: 学んだことまとめ 2011/11/14〜11/25 | KRAY Inc

  26. Rich says:

    I’ve used some of this information to produce a more complete deploy guide and example files (and not just for Amazon):

    http://gun.io/blog/tutorial-deploy-node-js-server-with-example/

  27. Pingback: Tagging the Web Daily 05/25/2012 « PAB Skunkworks Weblog

  28. Pingback: Useful Node.js Tools, Tutorials And Resources « Dao Hoang Tu

  29. Pingback: Useful Node.js Tools, Tutorials And Resources - Goodfav Howto

  30. Pingback: vimtronner: A Multiplayer, Command-line vim Trainer built on Node.js and Socket.io | The Carbon Emitter

  31. Pingback: Useful Node.js Tools, Tutorials And Resources | Smashing Magazine | Hugo Mineiro Portfolio

  32. Pingback: 有用Node.js的工具,教程和资源 | 前端开发

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>