Marcus Node Bits: Deploying to Heroku (and MongoHq)

Posted by Marcus Hammarberg on April 21, 2014
Stats
I've been doing something for real! A very simple little polling site, that actually turned out pretty ok (saved the UI but I have a friend brushing that up for me) and might be useful.
It's built with KoaJs, of course, and using MongoDb as database. Basically you can create a "question", tag it with some meta data and then send a link to a page where you can start receiving answers. And there's some very basic "export to excel"-reporting. Simple stuff. I spent maybe 3-5 hours altogether on it, in the hospital bed with my son in the bed next to me. He was pretty ok, so the concentration was not on top on either tasks for me. Bad!

This Sunday I wanted to deploy the first version of it. To Heroku. It went pretty smooth but I wanted to share my story and some problems I ran into.

I've been doing something for real! A very simple little polling site, that actually turned out pretty ok (saved the UI but I have a friend brushing that up for me) and might be useful.
It's built with KoaJs, of course, and using MongoDb as database. Basically you can create a "question", tag it with some meta data and then send a link to a page where you can start receiving answers. And there's some very basic "export to excel"-reporting. Simple stuff. I spent maybe 3-5 hours altogether on it, in the hospital bed with my son in the bed next to me. He was pretty ok, so the concentration was not on top on either tasks for me. Bad!

This Sunday I wanted to deploy the first version of it. To Heroku. It went pretty smooth but I wanted to share my story and some problems I ran into.

For the most part I was impressed over the smoothness and "it just works"-factor throughout the deployment of my application.  This article is a great starting point for NodeJs applications and I suggest your read it before you start. 

Setting up Heroku

First you of course need to sign up with Heroku, so go ahead and create an account there if you haven't already.
Locally you need something called the Heroku tool belt. It's an easy install from their site and then you can read this to get started. The tool belt is basically just a bunch of command line commands that is really powerful.

The first things you probably use the tool belt for is probably:
  • heroku login - to authenticate with the Heroku-site credentials
  • heroku create [appname] - create an Heroku application in a directory and on the Heroku site. And setup a nice link between them that is the real power of Heroku. 
  • heroku keys:add - add your ssh-keys to let Heroku know that you are you. Read this.
The last point was also my first gist. I'll soon come back to it. But I need to explain one more command that you need to know about:
  • git push heroku [branch] - remember above where we created the application. This also sets up a git remote for you. Aptly named heroku. This is awesome because it means that we can move code to Heroku by a normal git push. If you're new to git have a look here. 

Error: git push heroku master -> Permission denied (publickey)

I was happy. Everything had gone so great. I had installed and run the Heroku tool belt command. They all worked like a charm. I even started to think that I knew what I was doing. Then I pushed to Heroku for the first time:
git push heroku master
Permission denied (publickey).
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
This was strange. I had ssh-keys in place (if you have not, read this article) since I was using GitHub that used ssh-keys too. But apparently Heroku wanted them to be in special files called "id_rsa" and "id_rsa.pub". I didn't have them. I had GitHub and GitHub.pub. Thank you StackOverflow.

package.json and the engine-node

Oh yeah... almost forgot. I'm of course using KoaJs for the app. I got tired of writing nested functions... As you remember Koa needs a version of Node that is later than the current version. You need to tell Heroku that you're planning to use another version of node also, otherwise it will use the latest stable version.

Luckily this is super simple. In you package.json file just define a node called "engines" and give it the version of Node you're using. Like this:
"engines": {
    "node": "0.11.12"
}
Thank you Jonathan Channon for reminding me to write this. Tripped me up at first. 

MongoHq

Now I could push my code to Heroku. Great - but I needed a database as well. Luckily Heroku is built around modules that you add to your application. In Heroku-speak: addons that you provision. I choose MongoHq since I had heard that name before. 

Installing the addon is super simple: heroku addons:add mongohq
The addon is then added to your application on the Heroku site and configured as needed. But your are not using it in your application. 

Getting it to work with your app

In order to use MongoHq in your application you need to get hold of the URL to the MongoDb database. The MongoHq addon exposes this through a environment variable which you can get hold of in Node by doing: "process.env.MONGOHQ_URL".
You can see the settings for you application under https://dashboard.heroku.com/apps/[your application name]/settings.

Now, this poses a bit of a problem since you want to use your local MongoDb server when developing and the one in the cloud at MongoHq when you are running live. There's myriads of ways to solve this but I have dragged a little configuration utility around for a while. It's just a single file that exports an object with the configuration variables I need. Here is one incarnation of it:
The first lines sets up my database connection strings, and uses the MONGOHQ_URL if it is present. I can then use my configuration object when I create my database object (in this case using Monk) like this:
var config = require('../config')();
var monk = require('monk');
var wrap = require('co-monk');
var db = monk(config.mongoUrl);
Ok, that worked just fine. Exceptionally actually. Because it just worked. MongoHq rocks!

Problems and logging

Now I hade everything installed. I pushed "the button" to Heroku and Maw-maw-maw. I got a really strange error.

Error: Web process failed to bind to $PORT within 60 seconds of launch

When I opened my site (heroku open form the command prompt by the way) it just gave me a bland: the site is not working, contact your admin kind of message. Admin... hey that's me in this case. I should probably read some logs or something. 

Reading logs at the prompt is actually quite simple, albeit a bit verbose in it's output: heroku logs will flush the log before you eyes.  If the log is really big you can do "heroku logs -n 1500" (last 1500 events) or "heroku logs -t" (100 last events). 
But it's not very nice to read, nor searchable. 

We need better. We need Papertrail. Papertrail is a nice little addon that helps you read your log. Install it (heroku addons:add papertrail) and you get a dashboard for you app with a nice UI to see, read and search your logs. 

With that in place the Yak was shaved and I could get back to trying to figure out why my site didn't show. There were two problems that hindered me:
  1. I was using Nodemon to start my application. It was not in my dependencies. Bad Marcus! I added that and updated my "npm start" command to point to the nodemon in my node_modules-directory ("start": "./node_modules/nodemon/bin/nodemon.js --harmony app.js prod").
    If nothing of that made any sense to you read this first. And then this.
  2. I then ran into the "Web process failed to bind to $PORT within 60 seconds of launch" mentioned above. Let's talk more about that. 
Heroku dynamically assigns your app a port, so you can't set the port to a fixed number. Heroku adds the port to the env, so you can pull it from there. Very much like the MONGOHQ_URL above. We need to use the environment variable set dynamically by Heroku in the production case and our local port in the local case. If you scroll back up you can see that I do that in my config-object (line 18), where set the port of my object to either the port from Heroku or a static one (port: process.env.PORT || 5000,)

Conclusion

There's always bumps in the road. These were mine. Overall I was still very impressed with the smooth ride to live site in production that Heroku and MongoHq treated me to. 


Published by Marcus Hammarberg on Last updated