How I Got Node.js Running On A Linux Micro Instance Using Amazon EC2

Posted January 27, 2012 at 6:42 PM by Ben Nadel

Tags: Javascript / DHTML

In the past, I've dabbled with Node.js (a server-side JavaScript runtime environment) on my local MacBook Pro. If you know JavaScript, it's not too hard to get something up and running on your local machine. Putting Node.js out into the wild, however, is whole other beast. Not only am I mediocre at managing web servers in general, I happen to know almost nothing about Amazon EC2 (Elastic Compute Cloud), Linux / Unix, Git, SSH, ports, routing, processes, and just about everything else that goes into managing a Node.js deployment. After a couple of hours, some online tutorials, and a bit of trial and error, I finally got something working! I managed to keep a Node.js process running on a Linux Micro instance on Amazon EC2! For those who are interested, I thought I would share my experience.

DISCLAIMER: I could not do any of this without the knowledgable guidance of many other blogs. Please take whatever I say in this post with a grain of salt. I am likely going to mangle terminology and provide misinformation (accidentally, of course).

I wanted to see if I could get Node.js up and running using manual labor. If you are interested in a managed Node.js platform as a service (PaaS), you might want to check out Nodejitsu. They provide a command-line tool that makes hosting and deploying Node.js application much more of a black-box experience.

For the following screenshots, please click on the smaller versions to view larger (1024 x 768) versions.

In order to deploy Node.js on an Amazon EC2 instance, the first thing you need to do is get yourself an EC2 (Elastic Compute Cloud) instance. Log into Amazon Web Services (AWS) and select the EC2 tab. On the EC2 landing page, you'll want to select "Key Pairs". Theoretically, you can do this as part of the Launch workflow; however, I found that I could not get past Step 1 without doing this beforehand.


 
 
 

 
 Deploying Node.js on Amazon EC2 (Elastic Compute Cloud). 
 
 
 

I don't fully understand what a Key Pair is; but, from what I can gather, it's a way to establish a trusted, authenticated connection between your computer (the client) and the server during an SSH operation. From the Key Pairs screen, create a new key pair:


 
 
 

 
 Deploying Node.js on Amazon EC2 (Elastic Compute Cloud). 
 
 
 

Enter the name of your key pair.


 
 
 

 
 Deploying Node.js on Amazon EC2 (Elastic Compute Cloud). 
 
 
 

Once you've created the Key Pair, Amazon should prompt you to save the private key. Make sure you know where the file gets saved on your local machine as you'll need to use it in subsequent step.


 
 
 

 
 Deploying Node.js on Amazon EC2 (Elastic Compute Cloud). 
 
 
 

Once you've downloaded the PEM file (private key), return to the EC2 landing page and click the Launch Instance button.


 
 
 

 
 Deploying Node.js on Amazon EC2 (Elastic Compute Cloud). 
 
 
 

This should take you into the launch wizard. Here, you can name your instance and select the Key Pair that we just created. I picked the Amazon Linux Quicklaunch option because that's what Kostas Mavropalias recommended on this blog. Apparently, the 64-bit version works well with Node.js.


 
 
 

 
 Deploying Node.js on Amazon EC2 (Elastic Compute Cloud). 
 
 
 

Once you've named and selected your instance, click Continue. This will take you to a confirmation page. On this page, take note of which security group is assigned to this instance. We will need to make some edits to this group to allow HTTP and TCP access.


 
 
 

 
 Deploying Node.js on Amazon EC2 (Elastic Compute Cloud). 
 
 
 

Now click Launch. This will immediately create and launch your new Linux micro instance. Once the instance starts, you will begin using billable processing time. But, don't worry! It's mad cheap - a free period followed by $.02 / hour! Booya, grandma!


 
 
 

 
 Deploying Node.js on Amazon EC2 (Elastic Compute Cloud). 
 
 
 

Click Close to return to the EC2 landing page.

Now, we need to go into the Security Groups to edit the public access permissions for this machine.


 
 
 

 
 Deploying Node.js on Amazon EC2 (Elastic Compute Cloud). 
 
 
 

Once on the Security Groups page, select the security group associated with our instance and then select the Inbound tab to see which ports are open.


 
 
 

 
 Deploying Node.js on Amazon EC2 (Elastic Compute Cloud). 
 
 
 

You should see that the SSH port (22) is open by default. That will allow us to remotely connect to the EC2 instance; however, in order to allow access from the web, we want to enable HTTP port 80 and a high-numbered TPC port for Node.js testing (before we pipe it into port 80).


 
 
 

 
 Deploying Node.js on Amazon EC2 (Elastic Compute Cloud). 
 
 
 

Once the rules have been defined, the changes need to be applied.

After the Security Groups have been updated, select Instances from the left-hand navigation. This should bring you to the list of running instances, where you'll want to select the newly created instance. This will bring up the details for the instance that includes the public DNS.


 
 
 

 
 Deploying Node.js on Amazon EC2 (Elastic Compute Cloud). 
 
 
 

Copy the public DNS value as we'll need it to SSH into the machine.

Our Amazon EC2 Linux micro instance is now up and running. It's time to install and configure Node.js! Go to the directory where you saved your PEM (key pair) private key. Create a text file called, "connect." This will be a Bash script that makes opening the SSH connection easier.

In the new "connect" file, define the SSH command using our PEM file and the public DNS value:

connect - Our SSH Connect Bash Script

  • #!/bin/bash
  •  
  • ## Connect to our EC2 instance using SSH. To do this, we have to
  • ## supply the PEM file using -i (Identity File) during connection.
  • ## For the user, we can use "ec2-user" and the public DNS value.
  • ssh \
  • -i ./NodeOnEC2Demo.pem \
  • ec2-user@ec2-174-129-82-198.compute-1.amazonaws.com

Notice that we are using "ec2-user" as the SSH user and our EC2 instance public DNS as the domain.

Save and close this file. Then, update the permissions so that it can be executed:

  • chmod +x ./connect

Once you've done this, you need to tighten the permissions on the PEM file. If too many people can access the PEM file, the SSH connection will be denied. Let's remove Read, Write, and Execute permissions for everyone but the current user (you):

  • chmod go-rwx ./NodeOnEC2Demo.pem

Once you've done this, you can connect to the EC2 instance by invoking the connect executable:

  • ./connect

Once you do this, the SSH connection will be opened. At this point, you'll probably be prompted to allow the untrusted connection:

The authenticity of host 'ec2-174-129-82-198.compute-1.amazonaws.com (x.x.x.x)' can't be established. RSA key fingerprint is x:x:x:x:x:x:x:x:x:x:x:x:x:.
Are you sure you want to continue connecting (yes/no)?

To be honest, I have no idea what this actually means. Just type "yes" and continue.

At this point, you'll be connected to the ec2-user's home directory. Now, we can update the machine software and install Node.js.

--------------------------
--------------------------

THANKS TO: Instructions for updating the computer and installing Node.js, Git, and NPM (Node Package Manager) were all taken from this post by Kostas Mavropalias. I'm simply re-creating part of it here. This part of the demo should probably take like 20 minutes to download and compile everything.

Update Your EC2 Linux Box

  • sudo yum update

Install The GCC Compiler And Git

  • sudo yum install gcc-c++ make
  • sudo yum install openssl-devel
  • sudo yum install git
  • git clone git://github.com/joyent/node.git
  • cd node
  • git checkout v0.6.8
  • ./configure
  • make
  • sudo make install

Add User's Directory To BIN Paths

  • sudo su
  • nano /etc/sudoers

Once inside the Nano editor, scroll to where you see the line:

Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin

Append the following value, ":/usr/local/bin", to the end of that line. Save the file and exit the Nano editor.

Install NPM - The Node Package Manager

  • git clone https://github.com/isaacs/npm.git
  • cd npm
  • sudo make install

--------------------------
--------------------------

Now that we have all of our core components installed, go back to the home directory of the machine and create a directory for our Node.js site:

  • cd ~/
  • mkdir site
  • cd site

I'm putting it in the home directory; but, from the feedback I got on Twitter, a lot of people would put this in the "/var/" directory somewhere.


 
 
 

 
 Where should I store WWW diretory on a Unix / Linux server. 
 
 
 

Once you're in the "site" directory, create the hello world file for our Node.js application. This will listen for requests coming in on port 8080 and return a static response:

server.js - Our Node.js Server File

  • // Load the necessary servers.
  • var sys = require( "sys" );
  • var http = require( "http" );
  •  
  • // Create our HTTP server.
  • var server = http.createServer(
  • function( request, response ){
  •  
  •  
  • // Create a SUPER SIMPLE response.
  • response.writeHead( 200, {"content-type": "text/plain"} );
  • response.write( "Hellow world from AWS!\n" );
  • response.end();
  •  
  •  
  • }
  • );
  •  
  • // Point the HTTP server to port 8080.
  • server.listen( 8080 );
  •  
  • // For logging....
  • sys.puts( "Server is running on 8080" );

You'll notice that our Node.js server is set to listen to port 8080. For security reasons, we're not supposed to allow non-core services to listen to port numbers below 1024. In order to allow requests on the standard HTTP port, 80, to be handled by our Node.js server on port 8080, we need to add some port forwarding.

Thanks to this blog post by Steve Kemp, setting up port forward is rather trivial with the use of the machine's IP Tables. Simply type this in the console:

  • iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to 8080

This seamlessly redirects port 80 to port 8080.

Ok, so now we have Node.js installed and able to listen to the standard HTTP port. Now, we need a way to keep our Node.js application running even after we logout of our EC2 instance. For this, we'll use the Forever module by Nodejitsu. Let's install Forever using our Node Package Manager (NPM):

  • sudo npm install forever

This should download a whole bunch of stuff into our "site" directory. Once it's done, we can use Forever to launch our Node.js server. However, since the command for Forever is somewhat complex, I am going to turn it into a Bash command file:

start - The Bash Script To Invoke Forever (And Start Node.js)

  • #!/bin/bash
  •  
  • # Invoke the Forever module (to START our Node.js server).
  • ./node_modules/forever/bin/forever \
  • start \
  • -al forever.log \
  • -ao out.log \
  • -ae err.log \
  • server.js

This command defines a number of log files that can be used to log the output and errors of our Node.js site as it runs. I'd like to put those log files in a sub-directory; however, I could not figure out how to define the file paths in such a way that actually worked.

As before, we need to add execute permissions to this file in order to be able to run it:

  • chmod +x ./start

Before we actually invoke Forever, however, let's create a Bash script that allows us to stop our script, should we need to:

stop - The Bash Script To Invoke Forever (And Stop Node.js)

  • #!/bin/bash
  •  
  • # Invoke the Forever module (to STOP our Node.js server).
  • ./node_modules/forever/bin/forever stop server.js

And apply the right permissions:

  • chmod +x ./stop

And now, we're ready to rock!!! Let's kick the tires and light the fires. Execute our Start Bash script:

  • ./start

This will invoke the Forever module and start our Node.js server (server.js). It should output something like:

info: Forever processing file: server.js

You'll notice that calling Forever puts you back into the command-line. At any time, you can invoke the Stop command to end the Node.js server:

  • ./stop

Or, you can simply logout of your EC2 server and let the Node.js server run.

But, does it actually work? Try testing your public DNS in your web browser to see if it works. In this demo, that would be:

http://ec2-174-129-82-198.compute-1.amazonaws.com

Hopefully, if everything went smoothly, you should get the following page output:

Hellow world from AWS!

NOTE: Yes, I see the extra "w"... I'm way too tired to fix it at this point.

Well, that's about all that I understand at this point. You can try to ask me questions; but, it is unlikely that I'll really be able to answer them. Like I said, I just got this to work for the first time. I definitely need to learn more about Unix servers and commands - I'm mostly feeling around in the dark.


You Might Also Be Interested In:



Reader Comments

Jan 28, 2012 at 9:45 AM // reply »
1 Comments

Nice post!

And from there,it would be nice to have an nginx proxy to redirect incoming requests to your local instances (in case you want to use serveral domains app1.mydomain.com, app2.mydomain.com redirected to local apps: localhost:8081, localhost:8082)

And also, in case the server restarts, you may need to add proper application initialization scripts to /etc/init.d to start them as a service.


Jan 28, 2012 at 12:05 PM // reply »
12 Comments

@ben, my new favorite node server for screwing around is actually the beaglebone. Been pretty fun to actually use node to integrate with real world physical devices.

http://beagleboard.org/bone
http://www.youtube.com/watch?v=9JBYDbSpGfo


Feb 3, 2012 at 10:49 PM // reply »
1 Comments

Wow this was really helpful!

Only thing I would add is you need to update your .bash_profile after you edit the secure_path. This is what I did:

$ . ~/.bash_profile

Otherwise, NPM won't be found.


Feb 20, 2012 at 2:00 AM // reply »
1 Comments

Is there a reasy why you didn't use the yum package?

sudo yum localinstall --nogpgcheck http://nodejs.tchol.org/repocfg/fedora/nodejs-stable-release.noarch.rpm

sudo yum install nodejs


Feb 20, 2012 at 10:12 AM // reply »
11,314 Comments

@Ivan,

I've seen people mention nginx, though I don't really know much about it. I'll have to look more into it. And thanks for the init.d pointer; I'm super new to any kind of Unix-style system management, so that kind of stuff really escapes me.

@Anthony,

Very interesting looking stuff. I love all this plug-n-play kinds of real-world technology that is coming out! It's like the next generation of "lego mind-storm."

@Matt,

I had some issues with the "su" command. I think that launched a completely new terminal session. Once I exited *out* of that one, I was able to find NPM and NODE in the bin directories.

That sort of stuff is out of my understanding of use Unix sessions really work, though.

@Curious,

I don't know much about Yum. When I was reading up on how to do this, Yum was only used for the system update, not Git. We have a case here of "monkey see, monkey do." It wasn't an educated choice on my part.


Apr 9, 2012 at 6:05 PM // reply »
1 Comments

Awesome tutorial to start with node.js+EC2!!!!.

Anyway it surprises me a lot how difficult is using node.js with EC2, specially when you compare doing the same with some PaaS such as Heroku or Cloud Foundry.


Jun 15, 2012 at 7:53 PM // reply »
1 Comments

Hi,

Thanks for the info, it exactly what i was looking for, very well explained for people who are not good at server side programming (includes me). i am however stuck .

i am creating a connect script file like you said but when i type this for the next step:

  • chmod +x ./connect

it says no such file or directory, so i saved it as .txt file connect.txt

  • chmod +x ./connect.txt

goes through without anyproblem

however again when i do ./connect it says no such file or directory , and now if i do

  • ./connect.txt

it throws :

  • -bash: ./connect.txt: /bin/bash^M: bad interpreter: Operation not permitted

Please help
thanks.


Jun 18, 2012 at 5:41 AM // reply »
1 Comments

hi,

i did everything as u have written upto the point of creating the start bash script file. However,

  • chmod +x ./start

gives Operation Not Permitted.

what to do?


Jul 16, 2012 at 2:16 AM // reply »
1 Comments

The chicken or the egg?

I've been trying to figure out if one installs npm with node or node with npm? This website seems to say you install node and it comes with npm: http://www.theatreinla.com/tictop.php. And the blog here on bennadel seems to be telling me that NPM installs Node. So I was wondering if someone could clear this up for me please?

-Nic


Ron
Sep 13, 2012 at 3:32 AM // reply »
1 Comments

after running this command:
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to 8080

I am unable to access the server via browser, it says unable to connect.

what do i need to do?

please help


Nov 21, 2012 at 9:15 AM // reply »
1 Comments

Hi,

1. I have installed slackware14.0 (64bit) in my local machine.
2. I have created the 10 gb image space in slackware machine using below command.?(dd if=/dev/zero of=slack14.img bs=1M count=10075). and mount the image in slack14.img.?mount -o loop slack14.img /mnt/slack1464.
3. I have format the image (slack14.img)
4. I have installed the custom package through ruby script. The custom package for?installed without any error.
After that While login the mounting image (/mnt/slack1464). and I have installed the package
I have bundle  the image with this aki(aki-427d952b) and upload to amazon.

I am unable to login the server, I am getting below error

6535502.145187] ip_tables: (C) 2000-2006 Netfilter Core Team
[6535502.145235] TCP cubic registered
[6535502.145244] NET: Registered protocol family 17
[6535502.245110] XENBUS: Device with no driver: device/console/0
[6535502.247428] EXT3-fs: barriers not enabled
[6535502.257460] EXT3-fs (xvda1): mounted filesystem with writeback data mode
[6535502.257484] VFS: Mounted root (ext3 filesystem) readonly on device 202:1.
[6535502.257779] Freeing unused kernel memory: 484k freed
[6535502.257953] kjournald starting. Commit interval 5 seconds
[6535502.471724] mount used greatest stack depth: 4296 bytes left
[6535512.662690] touch used greatest stack depth: 4120 bytes left
[6535576.762574] xenbus_dev_shutdown: device/console/0: Initialising != Connected, skipping
[6535577.114477] Restarting system.

earlier I have created the .img image in (slackware13.1 & 13.37) without any error.
But I am getting the error in Slackware14.0 64bit and 32bit only.

Thanks for advance.

BY?
David


Dec 25, 2012 at 10:08 PM // reply »
2 Comments

Hi there, thanks for this great article really helpful. I have a follow up question. What if i want to run a node on some other port say 3001 and without touching port 80 as it will be delivering the website. I tried node with other port but its not working for me. Any help would be great thanks.


Dec 25, 2012 at 10:10 PM // reply »
2 Comments

@Ron,

I had the same problem just do
iptables -t nat -D PREROUTING -p tcp --dport 80 -j REDIRECT --to 8080.

Your website will start working.


Feb 14, 2013 at 5:47 PM // reply »
1 Comments

I appreciate the post. My app is hosted on Nodejitsu right now, but I think I might eventually want to move it over to Amazon so I can have some more flexibility. For example, I'd like to use R within my app, but I don't think Nodejitsu supports it. Of course, with increased flexibility, comes increased complexity. It's going to take me a while to wrap my head around this.


Mar 12, 2013 at 9:17 PM // reply »
1 Comments

@Anthony Webb: I actually use node.js and EC2 to spawn system builds *from* my BeagleBone. The BeagleBone is underpowered to rebuild the kernel or distro, so I spawn it off with scripts. [1]

While the description above on getting node.js running on EC2 is quite useful, I find the scripting method far easier, especially to document and preserve/repeat.

[1] https://github.com/jadonk/validation-scripts/tree/master/ec2-build


Mar 12, 2013 at 9:44 PM // reply »
12 Comments

@Jason Krinder, that is pretty neat. Thanks for sharing! BTW, whats a guy got to do to get a hold of one of those new bones? :)



Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
Jun 19, 2013 at 2:01 PM
Experimenting With The Amazon Simple Storage Service (S3) API Using ColdFusion
I have coincidentally been beating my head against the S3 API for the last week or so. One big "gotcha" I had to work around was file names and paths containing spaces. Remember to URL Enco ... read »
Jun 19, 2013 at 1:27 PM
Using Slice(), Substring(), And Substr() In Javascript
very good article. By the way IE supports negative values in substr or slice in verson 10. ... read »
Jun 19, 2013 at 11:33 AM
Filter vs. ngHide With ngRepeat In AngularJS
In your assessment, is it correct to say that given a list of say 500 items its more performant to use the `ngHide` method over the `filter` method? ... read »
Jun 19, 2013 at 10:18 AM
ColdFusion Path Usage And Manipulation Overview
Anyone happen to know if the file created by getTempFile will be automatically removed at any point? Nothing mentioned in the docs, and restarting CF doesn't remove them, so it seems it needs manu ... read »
Jun 19, 2013 at 9:41 AM
Working With Inherited Collections In AngularJS
I actually just ran into this same situation with a demo I was putting together. Your implementation of multi-lvl $scope's > Mine :) ... read »
Jun 19, 2013 at 8:17 AM
My Experience With AngularJS - The Super-heroic JavaScript MVW Framework
@Prateek, to match a word or text you should use .toContain('word') that's a jasmine reference. website is : http://pivotal.github.io/jasmine/ ... read »
Jun 19, 2013 at 8:10 AM
My Experience With AngularJS - The Super-heroic JavaScript MVW Framework
Hi Guys, Actually i am doing e2e test of angular js of my project but i am not getting one thing that is how to press enter key through the test when my form is filled as i am not using a button but ... read »
Jun 18, 2013 at 9:20 PM
Mapping AngularJS Routes Onto URL Parameters And Client-Side Events
I couldn't find examples of passing multiple arguments using the when() routing statement so figured out through trial and error that you can pass multiple arguments using the following format: .whe ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools