Deploying a Node.js/socket.io app to Openshift

As a follow up to my previous article on how to Deploy Node.js & MongoDB app to AppFog, today I am going to explain how to deploy your app to Openshift.

I really like AppFog, however there is something really missing from their offerings and that is socket.io & support for websockets. As I continue working on my chat application I wanted to deploy it somewhere so I can do further testing and of course websocket support was a key thing.

Openshift gives 3 'gears' (instances) for free and their sizes are 'small' which means that you get the basic setup (512 MB - compare this with AppFog's 2GB and 1GB of disk space). In more scientific terms:

A Gear is a container with a set of resources that allows users to run their applications. OpenShift runs many Gears on each virtual machine and dynamically distributes Gears across them.

Here's what you need to do in order to get up and running with Openshift - I am assuming that you've already registered yourself. My preference is to use the command line interface but of course you can use their web user interface as well to achieve the same thing.

First things first, you need to install rhc - Openshift's cli interface. You can do that by executing the following command (on a unix system):

sudo gem install rhc

Once this tool is installed it's time to setup your environment - luckily, rhc has a built in command for this:

rhc setup

I have setup an authorisation token with my server - so this means that I can easily connect to my Openshift instances from my server.

Once this is done, we are ready to create an application and this can be achieved by executing the following statement:

rhc app create nodesocketapp nodejs-0.10

(to see what cartridges are available you can run rhc cartridge list)

Now comes the tricky bit. Deploying an app to Openshift is based on Git - basically everytime you push a change to your git repo locally, the changes will be pushed to Openshift which in turn will shut down your app, changes are copied over from your computer to Openshift, scripts such as npm install will be executed and finally your application will be started up again.

If you'd like to deploy an app that you already have under Git control my recommendation is that you create an Openshift branch. I'm going to explain how to do that now.

First, copy the Git URL that was automatically generated to you once you've created your application:

rhc app show nodesocketapp | grep Git

(rhc app show [appname] shows all the information about your app)

Navigate to your application folder on your locale machine and add the openshift as a remote:

git remote add openshift -f [git URL copied before]

Once this is done, merge your local code with the one found on openshift:

git merge openshift/master -s recursive -X ours

After the merge, you're ready to push your changes to Openshift:

git push openshift HEAD

From this point, everytime you make a change locally, you can just execute git push openshift to update your app online as well.

Once I've deployed my application I have run into a few issues. First of all the command bower install failed. I tried the installation in two ways:

  • ssh into my instance - you can do this by executing rhc ssh [appname]. Because of the authorisation key that we setup earlier, this will work automatically (for the first time, you'll need to say yes to permanently adding the RSA fingerprint). Your app is deployed under app-root/repo and here if you try install the bower packages, you'll most likely get a 'bash: bower: command not found' error message.
  • the second option that I tried was to navigate into the appropriate node_modules folder while still ssh-d into the server and execute bower from there:
    cd node_modules/bower/bin
    ./bower install
    However this trowns an EACCESS, permission denied '/var/lib/openshift/[instance-id]/.local' error message - you don't have the permission to write the home folder.

The solution is simple. As part of the npm install you can add various variables and also execute commands that can be found in your package.json file - add the following section (or extend the script section with these lines if you already have this parameter in place:

"scripts": {
    "postinstall": "export HOME=/var/lib/openshift/[instance-id]/app-root/runtime/repo; ./node_modules/bower/bin/bower install"
  },

This will setup a new HOME directory - that is writable by you as well as automatically invoke bower install.

I also recommend that you lock down your dependency revisions by creating an npm-shrinkwrap.json file. To do this install the shrinkwrap npm package and execute npm shrinkwrap.

Finally, there are some code modifications that you will probably need to do as well in order to make websockets functional.

Make sure that you use the right ports for your app so please add the following lines to your Node.js/Express.js configuration (output trimmed):

var express = require('express')
, app = express()
, server = require('http').createServer(app)
, io = require("socket.io").listen(server)
//... more config and code
app.set('port', process.env.OPENSHIFT_NODEJS_PORT || 3000);
app.set('ipaddr', process.env.OPENSHIFT_NODEJS_IP || "127.0.0.1");
//... code to continue

And now something important: regardless of what port you've been using during your testing, when you deploy your app to Openshift, you need to use the above ports and from the client side you need to use port 8000:

var socket = io.connect("http://your-app-url.rhcloud.com:8000");

And this is it. If you've done everything right, you should be able to run your Node.js/socket.io app on Openshift.

I have updated my chat app on GitHub to be 'Openshift ready' so feel free to check that out and play around with it. (Note that there are some things that you'll still need to change - e.g. the websocket in the repo tries to connect to localhost on port 3000.)

I found a few bugs in my code that I need to fix (mostly happening when accessing the page from a mobile browser) so I'll be busy updating the repo.

Good luck with the deployment.

Show Comments