Deploy Node.js & MongoDB app to AppFog
Older Article
This article was published 12 years ago. Some information may be outdated or no longer applicable.
I’ve written a few articles about various applications using technologies like Node.js, MongoDB, AngularJS and so on. Some of you asked for online demos of the working apps. I’ll admit I kept ignoring those requests because I didn’t know where to deploy them. I know Amazon gives away a free EC2 instance, but I’m using mine for other things and didn’t want to spend money on simple demo apps.
After some digging, I found a PaaS provider called AppFog (now defunct). (Quick note: I’m not affiliated with them in any way. I’m using them simply because they fit my needs.)
AppFog, unlike a raw EC2 instance, is a managed service. If you’re deploying a Node.js app, you don’t need to install anything. You just spin up your instance and all the dependencies are already there. The downside: if you need a different version of Node, you can’t upgrade.
Their free package comes with:
-
2 GB free RAM (the most generous offer I’ve seen)
-
A maximum of 8 service instances (more on this below)
-
100MB storage per MySQL or PostgreSQL instance
-
10MB RAM and 6 concurrent connections for MongoDB (plus Redis and RabbitMQ)
-
5GB data transfer per month
-
100 requests per second
For demoing an app, that’s more than enough.
After registering, you’ve got two options: create your first app via their GUI, or via a command line tool called af. I’ll walk through the latter. My server is Ubuntu 12.04 LTS, so the instructions below are specific to that.
First, set up af itself. The only requirement is Ruby version 1.8.7 or higher. If you’ve got that, run gem install af. Then navigate to the folder containing your code and run af login. It’ll prompt for your AppFog username and password. Enter the right details and you’ll see a success message.
Time to create an application inside AppFog. Run af push your-app-name. You’re giving your application a name here, and it’ll show up in your application list (I’ll show how to access that later). The tool asks a few questions:
af push airport-api
Would you like to deploy from the current directory? [Yn]:
Detected a Node.js Application, is this correct? [Yn]:
1: AWS US East - Virginia
2: AWS EU West - Ireland
3: AWS Asia SE - Singapore
4: HP AZ 2 - Las Vegas
Select Infrastructure: 2
Application Deployed URL [airport-api.eu01.aws.af.cm]:
Memory reservation (128M, 256M, 512M, 1G, 2G) [64M]: 128M
How many instances? [1]:
AppFog automatically detects the application type from the folder contents. It also offers a choice of hosting location. I picked an Amazon server in Ireland.
I’ve paused here deliberately because the next question is about services. Remember, the free account allows up to 8 services. A service can be a MySQL instance, a MongoDB instance, and so on. You can only have 8, so if you’ve got 3 or 4 apps using MongoDB, I’d recommend setting up one MongoDB service and using different collections to store the data (if that’s feasible). With that in mind, let’s create a service and assign it to our app. If you’ve set up a service before, you’ll get the first question. Otherwise, the “Create service” prompt appears:
Bind existing services to 'contact-manager'? [yN]:
Create services to bind to 'contact-manager'? [yN]: y
1: mongodb
2: mongodb2
3: mysql
4: postgresql
5: rabbitmq
6: redis
What kind of service?: 2
Specify the name of the service [mongodb2-eb085]:
Create another? [yN]:
Would you like to save this configuration? [yN]:
Creating Application: OK
Creating Service [mongodb2-eb085]: OK
Binding Service [mongodb2-eb085]: OK
Uploading Application:
Checking for available resources: OK
Processing resources: OK
Packing application: OK
Uploading (43K): OK
Push Status: OK
Staging Application 'airport-api': OK
Starting Application 'airport-api': OK
The difference between the two MongoDB options: the first is an older version (v1.8), the second is newer (v2.4.8). Those version numbers were accurate at the time of writing.
You might hit a few errors here. That’s normal. AppFog may complain about a missing shrinkwrap file. Just edit your package.json and add a dependency for the shrinkwrap npm module. Then run npm install or npm install shrinkwrap, followed by npm shrinkwrap. This creates an npm-shrinkwrap.json file.
The second problem I ran into: AppFog doesn’t support nodemon (at least I could never make it work). I deployed my app, got error messages related to nodemon, removed the dependency from package.json, deleted the relevant folder from node_modules, only to find that af update (which pushes updates to AppFog after a code change) failed because the node_modules nodemon folder was missing. To fix this, delete npm-shrinkwrap.json and run npm shrinkwrap again. Test with af update.
Note: if you’d like to keep using nodemon, add a .afignore file to your project with a path to the directory you want excluded when pushing updates to AppFog. Same concept as .gitignore.
To see your applications, use af apps, which returns something like this:
Your app is in place, but the MongoDB connectivity isn’t configured yet. Sorting that out is easy. I’ll show two approaches. The first comes from the AppFog documentation.
Open the file where you’ve got your MongoDB connection setup and add the following above the point where you connect to the database:
if (process.env.VCAP_SERVICES) {
var env = JSON.parse(process.env.VCAP_SERVICES);
var mongo = env['mongodb2-2.4.8'][0]['credentials'];
} else {
var mongo = {
hostname: 'localhost',
port: 27017,
username: '',
password: '',
name: '',
db: 'db',
};
}
var generate_mongo_url = function (obj) {
obj.hostname = obj.hostname || 'localhost';
obj.port = obj.port || 27017;
obj.db = obj.db || 'test';
if (obj.username && obj.password) {
return (
'mongodb://' +
obj.username +
':' +
obj.password +
'@' +
obj.hostname +
':' +
obj.port +
'/' +
obj.db
);
} else {
return 'mongodb://' + obj.hostname + ':' + obj.port + '/' + obj.db;
}
};
var mongourl = generate_mongo_url(mongo);
var mongoose = require('mongoose');
//For local environment: mongoose.connect(mongourl);
var Schema = mongoose.Schema;
var ContactSchema = new Schema({
name: { type: String, required: true },
phone: { type: String },
email: { type: String },
facebook: { type: String },
twitter: { type: String },
skype: { type: String },
});
//etc etc etc
Note: If you selected the ‘mongodb2’ service, use the code above. For the ‘mongodb’ service, use:
var mongo = env['mongodb-1.8'][0]['credentials'];
For another approach, have a look at this DB config file on GitHub.
The last thing I’ll cover is af tunnel. This tool lets you remotely connect to your service (in our case MongoDB) and run queries against it. It’s extremely useful. You can inspect your data and import new data.
First, install a tool called Caldecott by running gem install caldecott. (I had an issue where my Ubuntu system demanded Ruby greater than 1.9.3, which I already had. So I updated to 2.0.0, which caused more problems. I reverted to 1.9.3 and caldecott installed without complaint. Still baffles me.)
Once set up, you’ll need two terminal windows. One runs the tunnel, the other handles the actual database connection.
In the first terminal, run af services to list all services on your account. Pick one from the provisioned services and run af tunnel [servicename]. You should see something like this:
In the second window, use the username/password combination to connect to the database via port 10000: mongo --port 10000 -u[username] -p[password] db (don’t close the first window, or you’ll kill the tunnel):
That’s the lot. I hope some of you give AppFog a try. It’s a solid free service, and once you wrap your head around creating an app and configuring it for their environment, deploying gets very easy. For more details, check their AF CLI reference page (AppFog has since shut down).
And here’s a starting point: if you don’t have a Node.js / MongoDB app handy, feel free to use the one I put together on GitHub. The data.json file contains all the airport information. You’ll need to import that dataset into MongoDB using mongoimport first, via the tunnelling method explained above.
Happy deploying!