Getting Started with Node.js on The Cloud

In my new job at salesforce.com I’m incredibly exited about getting into Heroku, a Platform as a Service provider / Cloud Application Platform. In a future blog post I’ll provide more details on what Heroku is and how it works. But if you are like me the first thing you want to do when learning a new technology is to take it for a test drive. I decided to take my Heroku test drive using the recently announced Node.js support. I’m new to Node.js, but at least I know JavaScript. Heroku also offers Ruby / Rails support but I don’t know Ruby – yet. So let me walk you through the steps I took (and that you can follow) to get started with Node.js on the Heroku Cloud.

Step 1) Sign up for Heroku

Step 2) Install the Heroku command line client

Step 3) Login to Heroku via the command line:

heroku auth:login

Step 4) Install git

Step 5) Install Node.js

Step 6) Create a Node.js app

I started by building a very simple “hello, world” Node.js app. In a new project directory I created two new files. First is the package.json file which specifies the app metadata and dependencies:

{
  "name": "hellonode",
  "version": "0.0.1",
  "dependencies": {
    "express": "2.5.11"
  },
  "engines": {
    "node": "0.8.4",
    "npm": "1.1.45"
  }
}

Then the actual app itself contained in a file named web.js:

var express = require('express');
 
var app = express.createServer(express.logger());
 
app.get('/', function(request, response) {
  response.send('hello, world');
});
 
var port = process.env.PORT || 3000;
console.log("Listening on " + port);
 
app.listen(port);

This app simply maps requests to “/” to a function that sends a simple string back in the response. You will notice that the port to listen on will first try to see if it has been specified through an environment variable and then fallback to port 3000. This is important because Heroku can tell our app to run on a different port just by giving it an environment variable.

Step 7) Install the app dependencies with npm:

npm install .

This uses the package.json file to figure out what dependencies the app needs and then copies them into a “node_modules” directory.

Step 8) Try to run the app locally:

node web.js

You should see “Listening on 3000″ to indicate that the Node.js app is running! Try to open it in your browser:
http://localhost:3000/

Hopefully you will see “hello, world”.

Step 9) Heroku uses a “Procfile” to determine how to actually run your app. Here I will just use a Procfile to tell Heroku what to run in the “web” process. But the Procfile is really the foundation for telling Heroku how to run your stuff. I won’t go into detail here since Adam Wiggins has done a great blog post about the purpose and use of a Procfile. Create a file named “Procfile” in the project directory with the following contents:

web: node web.js

This will instruct Heroku to run the web app using the node command and the web.js file as the main app. Heroku can also run workers (non-web apps) but for now we will just deal with web processes.

Step 10) In order to send the app to Heroku the files must be in a local git repository. To create the local git repo, run the following inside of your project directory:

git init

Now add the three files you’ve created to the git repo:

git add package.json Procfile web.js

Note: Make sure you don’t add the node_modules directory to the git repo! You can have git ignore it by creating a .gitignore file containing just “node_modules”.

Commit the files to the local repo:

git commit -m "initial commit"

Step 11) Create an app on Heroku:

heroku create

A default / random app name is automatically assigned to your app.

Step 12) Now you can push your app to Heroku! Just run:

git push heroku master

You should see something like:

Counting objects: 8, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 729 bytes, done.
Total 6 (delta 2), reused 0 (delta 0)
 
-----> Heroku receiving push
-----> Node.js app detected
-----> Resolving engine versions
       Using Node.js version: 0.8.4
       Using npm version: 1.1.41
-----> Fetching Node.js binaries
-----> Vendoring node into slug
-----> Installing dependencies with npm
       npm WARN package.json hellonode@0.0.1 No README.md file found!
       npm http GET https://registry.npmjs.org/express/2.5.11
       npm http 200 https://registry.npmjs.org/express/2.5.11
       npm http GET https://registry.npmjs.org/express/-/express-2.5.11.tgz
       npm http 200 https://registry.npmjs.org/express/-/express-2.5.11.tgz
       npm http GET https://registry.npmjs.org/connect
       npm http GET https://registry.npmjs.org/mime/1.2.4
       npm http GET https://registry.npmjs.org/qs
       npm http GET https://registry.npmjs.org/mkdirp/0.3.0
       npm http 200 https://registry.npmjs.org/qs
       npm http 200 https://registry.npmjs.org/mkdirp/0.3.0
       npm http 200 https://registry.npmjs.org/mime/1.2.4
       npm http 200 https://registry.npmjs.org/connect
       npm http GET https://registry.npmjs.org/qs/-/qs-0.4.2.tgz
       npm http GET https://registry.npmjs.org/connect/-/connect-1.9.2.tgz
       npm http GET https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz
       npm http GET https://registry.npmjs.org/mime/-/mime-1.2.4.tgz
       npm http 200 https://registry.npmjs.org/qs/-/qs-0.4.2.tgz
       npm http 200 https://registry.npmjs.org/mime/-/mime-1.2.4.tgz
       npm http 200 https://registry.npmjs.org/connect/-/connect-1.9.2.tgz
       npm http 200 https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz
       npm WARN package.json connect@1.9.2 No README.md file found!
       npm http GET https://registry.npmjs.org/formidable
       npm http 200 https://registry.npmjs.org/formidable
       npm http GET https://registry.npmjs.org/formidable/-/formidable-1.0.11.tgz
       npm http 200 https://registry.npmjs.org/formidable/-/formidable-1.0.11.tgz
       express@2.5.11 node_modules/express
       ├── qs@0.4.2
       ├── mime@1.2.4
       ├── mkdirp@0.3.0
       └── connect@1.9.2 (formidable@1.0.11)
       npm WARN package.json hellonode@0.0.1 No README.md file found!
       npm WARN package.json connect@1.9.2 No README.md file found!
       express@2.5.11 /tmp/build_h2gd35fmkgzm/node_modules/express
       connect@1.9.2 /tmp/build_h2gd35fmkgzm/node_modules/express/node_modules/connect
       qs@0.4.2 /tmp/build_h2gd35fmkgzm/node_modules/express/node_modules/qs
       mime@1.2.4 /tmp/build_h2gd35fmkgzm/node_modules/express/node_modules/mime
       formidable@1.0.11 /tmp/build_h2gd35fmkgzm/node_modules/express/node_modules/connect/node_modules/formidable
       mkdirp@0.3.0 /tmp/build_h2gd35fmkgzm/node_modules/express/node_modules/mkdirp
       Dependencies installed
-----> Discovering process types
       Procfile declares types -> web
-----> Compiled slug size is 4.0MB
-----> Launching... done, v5
       http://fast-plateau-8288.herokuapp.com deployed to Heroku
 
To git@heroku.com:fast-plateau-8288.git
   26b4efc..6e333a2  master -> master

Now you should be able to connect to your app in the browser! An easy way to open the app in your browser is to run:

heroku open

To see your app logs (provisioning, management, scaling, and system out messages) run:

heroku logs

To see your app processes run:

heroku ps

And best of all, if you want to add more Dynos* just run:

heroku scale web=2

* Dynos are the isolated containers that run your web and other processes. They are managed by the Heroku Dyno Manifold. Learn more about Dynos.

That increases the number of Dynos running the app from one to two. Automatically Heroku will distribute the load across those two Dynos, detect dead Dynos, restart them, etc! That is seriously easy app scalability!

There is much more to Heroku and I’ll be continuing to write about it here. But in the meantime, check out all of the great docs in the Heroku Dev Center. And please let me know if you have any questions or problems. Thanks!

This entry was posted in Cloud, Heroku, JavaScript, Node.js. Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.
  • Keith

    I had some problems installing npm from source, which turned out to be caused by the version of Node.js that was installed on Ubuntu via apt-get. The Natty repo has version 0.2.6, so I removed it and compiled and installed from https://github.com/joyent/node/tree/v0.4.

    • http://www.jamesward.com James Ward

      Thanks Keith for pointing that out! The latest version I have is 0.4.8~natty1~ppa201105311835. Looks like I added the following PPA and forgot to document it!
      https://launchpad.net/~jerome-etienne/+archive/neoip

      I’ll update the instructions. Thanks again!

  • http://blog.superpat.com/ Pat Patterson

    Hi James – excellent writeup – I’ll link to it from my article at http://blog.superpat.com/2011/06/14/node-js-chat-demo-on-heroku/ :-)

    One useful nugget for you – if you do the git init before heroku create, you don’t need to do the git remote add heroku stuff – heroku create will do it for you.

    • http://www.jamesward.com James Ward

      Thanks Pat! Great stuff!!

  • Pingback: Node.js Chat Demo on Heroku « Superpatterns()

  • Anand

    http://boxysystems.com/index.php/step-by-step-instructions-to-install-nodejs-on-windows/ has detailed information on how to install nodeJS on windows using Cygwin.

    • http://www.jamesward.com James Ward

      Thanks for the link!

      • Anand

        For NPM install to work on cygwin, you need to create a file called “resolv.conf” under “/etc” and enter the following in that file

        nameserver 8.8.8.8
        nameserver 8.8.4.4

        Otherwise NPM will give the following error when trying to install packages:

        npm ERR! Error: ECONNREFUSED, Could not contact DNS servers
        npm ERR! at IOWatcher.callback (dns.js:74:15)
        npm ERR! Report this *entire* log at:
        npm ERR!
        npm ERR! or email it to:
        npm ERR!

  • Pingback: Using Node.js with Apex REST()

  • Krishnan

    @James There was yet another resource which was helpful in address common issues while trying to install node.js in addition to the link @Anand has provided http://ajaywhiz.posterous.com/installing-nodejs-on-windows-7

  • Krishnan
  • Abhijeet

    Hello james,
    I recently installed ruby installer and then ruby gems on my system.Then I entered “gem install heroku” on the prompt, but after doing so I could’nt install the Heroku command line client as I emcountered an error “file not in gzip format ” ,
    I would be really thankful if you could help me out on the same.

  • Pingback: Hosting the Todos example on Heroku « Brian Genisio's House of Bilz()

  • Pingback: Using Node.js to Host Development Web Services | Jeff Douglas - Technology, Coding and Bears... OH MY!()

  • mirza

    hey james getting an error
     !  Your key with fingerprint b1:21:b5:fd:e7:1e:aa:95:ef:20:5f:fe:d2:18:b0:79 is
     not authorized to access xxxx.

    fatal: The remote end hung up unexpectedlytried http://devcenter.heroku.com/articles/keys , but error is still their..!!

    • http://www.jamesward.com James Ward

      That means that the SSH key that is being used doesn’t have access to push to the app.  Have you associated that key with the Heroku account for the app you are pushing?

  • david

    Hi James,

    Looking at the https://devcenter.heroku.com/articles/nodejs there is a brief explaination about the worker.js but sadly no examples how to make a worker in javascript. (My worker needs to access  couchbd and do http stuff etc..)

    I did find an example in java https://github.com/heroku/devcenter-java-worker but I am a bit reluctant to switch to java while the web.js is in javascript…

    Have you an idea where I can find some more info on this? thx

    • http://www.jamesward.com James Ward

      A worker in Node.js can access CouchDB just like any other Node.js app.  But workers on Heroku can’t do HTTP.  Only web processes can talk HTTP.

      Can you provide more details on what you are looking for?

  • david

    That s too bad. The worker I need to implement needs to see if there are any messages (from couchdb) to push using C2DM and update the push task status afterwards(in couchdb). As I am not a ruby expert, I think I ll implement this in Java. I dont see why background workers cant make http connections to POST stuff. Isnt couchdb all in http btw?

    • http://www.jamesward.com James Ward

      Ahh, so you need outbound HTTP.  Sorry I misunderstood.  Workers can make any outbound connections.

      Is there a Ruby CouchDB client?  That would make it easier.

  • Pingback: Node.js Chat Demo on Heroku | WikiCloud()



  • View James Ward's profile on LinkedIn