How to Create a Node.js Web Server as an Amazon AWS EC2 Linux Instance

Amazon Web Services (AWS)

aws ec2 linux instance LogoCreating an Amazon AWS EC2 Linux instance is easier than you may think. There are few decisions to make and you can accept most default values. Once your instance is launched, it’s easy to SSH in, install Node.js and create your web server.

Creating an Amazon AWS EC2 Linux instance can be intimidating. Because AWS provides such low-level functionality, it can often feel as if you have to think-through a lot of details just to get your “Hello World!” application up-and-running. After walking through the process of spinning-up a server instance on AWS EC2, I found that the steps are not overly difficult. For the most part, there are only a few decisions to make, and in many cases you can accept the default values. Some of the concepts or terms might be difficult to understand at first, but for the most part they encompass pretty basic full-stack web development topics that you should have run across by now.

In this article, I will walk you through the steps needed to create and launch an Ubuntu Linux instance on AWS EC2. To be specific, we will create an Amazon AWS EC2 Linux Instance and then install Node.js and create an HTTP web server. Once our instance is launched, we will install Node.js and create a (very) bare-bones web server. A very important step to think about is towards the end: downloading your .pem file. This file contains the AWS credentials needed to SSH into your Linux instance. If anyone were to get their hands on this file, they could SSH into your Linux instance, which is bad. If you lost this file, then you will not be able to SSH into your Linux instance, which is bad too. So, keep that file in a safe place. For this article, I assume you already have an AWS account. If you do not have one, please take care of that first. It’s easy and there is no cost to sign up. You will need to provide a credit card, but that is for future billing purposes. Ok, let’s get started.

IMPORTANT NOTE: I kept all of the example images small for the sake of readability. Click on any thumbnail to open the full-sized image in a new window.


Creating an EC2 Instance

Go to the EC3 dashboard

You can go directly to the AWS EC2 Console: console.aws.amazon.com/ec2

Or, at the AWS Console, click “Services” in the upper-left-hand corner of the page, then click “compute”, and then “EC2”.

Click the “Launch Instance” button.

Launch Instance button


Choose an Amazon Machine Image (AMI) – Step 1

Step 1: Choose an Amazon Machine Image (AMI)

Choose Ubuntu Server 16.04 LTS (click the “Select” button)


Choose an Instance Type – Step 2

Step 2: Choose an Instance Type

Choose “t2.micro”
Click “Next: Configure Instance Details”


Configure Instance Details – Step 3

Step 3: Configure Instance Details

You can accept all default values on this page
Click “Next: Add Storage”


Step 4 – Add Storage

Step 4: Add Storage

Accept the default SSD side of 8GB.
Click “Next: Add Tags”


You can configure a tag here, but that is optional.
Click “Next: Configure Security Group”


Configure Security Group – Step 6

Step 6: Configure Security Group

By default, AWS configures SSH using TCP on port # 22. You will see a warning about the source value of 0.0.0.0/0. This is because right now we can SSH to our EC2 instance from any IP address in the world. Best practice is to restrict SSH access to just one or two IP address in order to maximize security, but for this article we can leave the default value. We also need to provide public HTTP access to our Node.js server via port 80.

Click “Add Rule” and select the type as “HTTP”, the default settings for this will use TCP as the protocol and expose port 80 to all IPs.

Choose HTTP

To launch your EC2 instance, click “Review and Launch”, then click “Launch”.


Review Instance Launch – Step 7

Step 7: Review Instance Launch

You’ll see the modal: “Select an existing key pair or create a new key pair”

You will be prompted to set up an SSH key which will give you access to your EC2 instance.

Select an existing key pair or create a new key pair modal

Choose “Create a new key pair”, and give the key a meaningful name.
After you enter a name for the key pair, click “Download Key Pair”

Download Key Pair

After you click “Download Key Pair”, a .pem file should start to download. You will need the contents of this file to create an SSH connection to your EC2 instance. It’s really important to keep this file in a safe place because anyone can SSH into your EC2 instance if they get their hands on it. Keep in mind: if you lose this file you will need to generate a new one.

After you have downloaded the .pem file, put that file in the following folder: ~/.ssh

Click “Launch Instance”


Launch Status

Launch Status

Click “View Instances”

Running Instances


SSH into your server

You’ll need to locate the public address of your EC2 instance. Right-click your instance and then click “Connect”. You’ll see the “Connect to Your Instance” modal

Connect to Your Instance modal

In the “Connect to Your Instance” modal, where it says: “Connect to your instance using its Public DNS”, copy the address you see.
This address should be in the following format: “ec2-1-2-3-4.compute-X.amazonaws.com”.


Open up your terminal application and execute the following command:

You will be connected to your EC2 Linux

Installing node and system dependencies

Install Node Version Manager

First we want to install NVM (Node Version Manager). Execute the following command:

Install Node

Before you install Node, you’ll need to log out and then reconnect with SSH. Log out by with the following command:

…and then re-establish your SSH connection.


Next, go to https://nodejs.org/en/ and check the latest version number of Node (for example, as of the date of this post, the latest version is: 8.9.4).
Install Node using the following command:

When the installation completes, verify the install using the following command:

Create a public HTTP endpoint

Create a new directory and move into it. For example:

Next initialize NPM with the following command:

…and accept all default values.

Now install Express.js using the following command:

Next we need to create the code for our web server. Execute this command:

This opens up the VIM editor. Press “a”, and then paste the following code into your terminal:

Now press the “esc” key, then “ : “, “w” and then “q”.

Finally, start the server:

Open Up Port 3000


Back in the AWS EC2 Console, on the left side where it says: “NETWORK & SECURITY”, click “Security Groups”
Right click the security group you set up and click “Edit inbound rules”.

Edit inbound rules

Click Add Rule.
Use a custom TCP rule on port 3000, set the “Source” to “Anywhere” and then click the “Save” button.

Edit inbound rules modal


Now you can view your EC2 instance in the browser using its Public DNS: ec2-1-2-3-4.compute-X.amazonaws.com

You should see the following message in your browser: “Your AWS EC2 Node.js Web Server is Working!”


Summary

This article covered only what you need to know in order to get your Node.js web server up-and-running. I only walked through the absolute minimum needed in order to spin-up an Ubuntu Linux instance on AWS EC2. One issue you’ll quickly run into is: uploading actual application files to your Linux instance. I’ll cover that in a new blog post. For now, I hope this article provided the information you needed to get your Amazon AWS EC2 instance launched and your new Node.js web server running.

Yikes! AWS Node / NPM ERR! enoent ENOENT: no such file or directory package.json

Node.js

Node.js LogoAWS’s Node deployment keeps telling me that it cannot find package.json, but it’s there! – Fortunately, this problem is easily solved.

AWS makes deploying your Elastic Beanstalk easy. Compress your build files, upload the ZIP and then deploy that application version. Lovely. But sometimes your application goes into a “warning” or “degraded” state, and then a visit to the application with a browser yields: “502 Bad Gateway“. Errrggggg…..

At this point, you look in the logs and see a cryptic message that says something like: “enoent ENOENT: no such file or directory package.json“. You double-triple-quadruple-check and yes, package.json is in-fact very much alive and well. So, of course your next thought it: “WTF???

I have run into this problem a few times and in each case, the problem was me: I zipped-up a folder, instead of the contents of a folder.

Do not compress an entire folder

Compressing the my project folder does not fix package.json problem

Let’s say your Node application is in a folder named: “myProject“. If you are compressing that folder, then this is your problem. You don’t want to compress a folder because when AWS un-zips that file, it will not know to look in the “myProject” folder that is created when the file is un-zipped.

Compress ALL of the items in  your project folder

Compressing the root files fixes package.json problem

What you want to do is: select EVERY file in the root of that folder (i.e. your Node application’s root folder), and then compress THOSE files. This will create a ZIP file that when un-zipped, creates the file structure that AWS expects. Now AWS will find package.json. This should solve the problem.

Compressing the root files fixes package.json problem

In the image above, I have zipped up the contents of the “myProject” folder, and created Archive.zip.

Upload the zipped file

Compressing the root files fixes package.json problem

Now, back in your AWS console, you can use the “Upload and Deploy” button to upload your ZIP file, and then deploy it.

Setting Your AWS-Hosted Node Application’s Port

Node.js

Node.js LogoWhen working locally, using an arbitrary port number is fine, but you need to get that property when deploying your Node application to AWS.

Technically, you can code-up a Node web server in less than ten lines of code. Most likely, your application will require a few more lines of code than that. But my point here is: getting a basic Node web server running is not terribly difficult.

Example # 1

In example # 1, I used port # 3000, but I could have used virtually any valid port number. When working locally this is for the most part a non-issue. As long as no other application is using the port you want to use, you chose one and then use it. Easy. This example does little more than say “Hello!”, but the point I’m trying to make is that your main JS file ends with the server.listen method, and you need to pass it a port number.

But when you attempt to deploy this code to your AWS Elastic Beanstalk instance, you will get a “503 Bad Gateway” error in your browser. The reason for this is: you don’t know which port should be used when calling the server.listen method. The great thing about AWS is that it provides a layer of abstraction for those kinds of details. In other words; AWS takes care of details such as which port to listen on. The downside here is that you have no way of knowing exactly which port that will be when you deploy your code.

Example # 2

In example # 2, we set a variable named: port. We attempt to assign the value of process.env.PORT to that variable. If that value is falsely, then we set it to 3000. The reason this works is; if our code is running on our AWS instance, then process.env.PORT will automatically be set and we will listen on that port. If we are running our code locally, then process.env.PORT will be undefined (or “falsely”). So, then our port variable will have a value of 300. This way, our code can run successfully on our AWS instance, or locally.

Setting AWS-Node.js Stormpath keys

Node.js

Stormpath Logoprocess.env can be used to set the environment variables you need when using the stormpath api in your aws-hosted node application

Stormpath provides amazing abstraction when it comes to authentication. There are certainly other services like this, but when it comes to security, Stormpath is not only popular, but well respected. This comes as no surprise as they simply make authentication easy.

I have to say that their documentation is for the most part very good. If Node is  your thing, they make it very easy to get up-and-running with their API. Their mailing list is also quite helpful.  At least a once or twice per week, I receive emails that link to interesting articles on their blog.

Recently, I was trying to setup a Node.js/Express.js application, leveraging their express-stormpath Node module. I was thinking to myself: “…hmmmm. There must be a step where I have to configure my secret key or something like that”. After some quality time with Google, I came across this article, that suggested the following:

Unix/Linux/Mac:

Windows:

(where “xxx” is your actual key)

Well, that is fine for working locally, but I knew if I wanted to deploy this as an AWS Elastic Beanstalk application, I needed to actually set these values somewhere.

Using process.env

I set the three environment variables I needed to be properties of process.env:
I

(where “XXX” is your actual key)

I took a look in the source code for the express-stormpath Node module and could see that it seemed to want to find these on process.env, so I think this approach should be fine. I’m still in the process of getting this Node.js/Express.js application up and running, but if you are faced with the same challenge, hopefully this helped you.