Complete Guide Deploy Node js app to AWS EC2 instance using AWS CodeDeploy and CodePipeline

Supun Sandaruwan
12 min readMar 23, 2024

--

image from linkedin

Here we discuss deploying Node js application to AWS and EC2 instance and for that

What is AWS EC2

Elastic Compute Cloud (EC2) instance is a virtual server in Amazon for running applications on the AWS infrastructure. We can think it is a remote machine that runs on the AWS server.

What is CodePipeline?

AWS CodeDeploy is a fully managed deployment service that automates software deployments to a variety of computing services such as Amazon EC2, AWS Fargate, AWS Lambda, and your on-premises servers. AWS CodeDeploy makes it easier for you to rapidly release new features, helps you avoid downtime during application deployment, and handles the complexity of updating your applications.

What happened here after setting up this process CodePipeline service is listening to changes in the GitHub repository that we provided. Here we can specify the git branch that needs to trigger changes. After changes happen in that specified branch CodePipeline service will trigger and give those changes to the CodeDeploy service. After that CodeDeploy service will run build the app by executing our code. After building it will run on the EC2 instance. This is the process that is happening here.

Let’s see how to integrate these services and how to deploy the node app. In this tutorial, I follow the steps below.

  1. Configure the node js app for deployment
  2. Create IAM roles for CodeDeploy and CodePipeline
  3. Create EC2 instance
  4. Create application in CodeDeploy
  5. Create pipeline
  6. View deployed app
  7. Error resolving

1. Configure the node js app for deployment

Here is what we need to provide instructions to deploy the app in the EC2 instance. For that, we need to create an appspec.yml file. This appspec.yml file should be in our root directory like below.

When deploying inside EC2 instance this yml file will be executed. There are 3 actions in appspec.yml and each action link with the shell script file(.sh file) in the scripts folder.

version: 0.0
os: linux
files:
- source: /
destination: /home/ec2-user/techflare-backend
hooks:
ApplicationStop:
- location: scripts/application_stop.sh
timeout: 300
runas: ec2-user
BeforeInstall:
- location: scripts/before_install.sh
timeout: 300
runas: ec2-user
ApplicationStart:
- location: scripts/application_start.sh
timeout: 300
runas: ec2-user

Important: here ec2-user is the username for the Amazon Linux ec2 instance. According to instance type using the correct username.

In appspec.yml file has several hooks provided by AWS and each hook will execute a related shell script file. Now let see what are the task of each shell script on the script folder.

before_install.sh

#!/bin/bash

#download node and npm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
. ~/.nvm/nvm.sh
nvm install node

#create our working directory if it doesnt exist
DIR="/home/ec2-user/express-app"
if [ -d "$DIR" ]; then
echo "${DIR} exists"
else
echo "Creating ${DIR} directory"
mkdir ${DIR}
fi

In this file ready the background before installing the app. It will download the node and npm and create the directory /home/ec2-user/express-app if not exist.

application_start.sh

#!/bin/bash

#give permission for everything in the express-app directory
sudo chmod -R 777 /home/ec2-user/techflare-backend

#navigate into our working directory where we have all our github files
cd /home/ec2-user/techflare-backend

#add npm and node to path
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # loads nvm bash_completion (node is in path now)

#install node modules
npm install

#start our node app in the background
npm start > app.out.log 2> app.err.log < /dev/null &

This file first creates the directory called home/ec2-user/express-app that has permission to access everyone. After that go to that directory(express-app) and set the path of npm and node. Next, install the node module which has in our package.json file. Finally, it will create the 2 files app.out.log and app.err.log. These two files are very important when application crashes happen. Normal logs are found on the app.out.log file and if any error happens it will display on the app.err.log file. You can view those files using the cat command.

application_stop.sh

#!/bin/bash
#Stopping existing node servers
echo "Stopping any existing node servers"
pkill node

If any kind of error happen when deploying run the application_stop.sh shell script file. To complete the starting boilerplate code lets add the app.js and package.json file like below.

app.js

const express = require('express');
const app = express();
const port = 3000;

app.get('/', (req, res) => {
res.send(`<h1>Express Demo App</h1> <h4>Message: Hello Success</h4> <p>Version 1.1</p>`);
})

app.get('/products', (req, res) => {
res.send([
{
productId: '101',
price: 100
},
{
productId: '102',
price: 150
}
])
})

app.listen(port, ()=> {
console.log(`Demo app is up and listening to port: ${port}`);
})

package.json

{
"name": "nodejs-express-on-aws-ec2",
"scripts": {
"start": "node app.js",
"build": "npm run build"
},
"version": "0.0.1",
"dependencies": {
"express": "4.17.1"
}
}

Now our starting boilerplate code is ready to deploy.

2. Create IAM roles for CodeDeploy and CodePipeline

First, you need to go to the AWS console and select the IAM web service. After selecting the Roles under the Access management section.

2.1 Create Code Deploy role for EC2 (AmazonEC2RoleforAWSCodeDeploy)

Now you can see like below background and click on the create role button.

image by author (2.1)

Now select the EC2 and click on the Next: permission button

image by author (2.2)

After that search for the ‘codedeploy’ in creating a policy table. And select the AmazonEC2RoleforAWSCodeDeploy like below. And click Next.

image by author (2.3)

After that click the Next: Review button to the below step.

image by author (2.4)

Then give a Role Name for this role and Click on the Create role button.

image by author (2.5)

After successfully creating the role you can see that role In the Role section like below.

2.2 Create Code Deploy role for CodeDeploy Service

Now you can see like below background and click on the create role button.

image by author (3.1)

Now you can see background like below

image by author (3.2)

Then Click on CodeDeploy and top and bottom places like the below image. Now click Next.

image by author (3.3)

After that, you will see the below screen and click next on both screens.

image by author (3.4)
image by author (3.5)

After successfully creating the role you can see that role In the Role section like below.

These are the two roles that we need to deploy our app.

3. Create EC2 Instance.

Here we are going to create an Amazon Linux instance. First, you need to go to the AWS console and select AWS EC2. After that select the instances section. It will look like below (If there is not any instance there not be a table like below). To create a new instance Click on the Launch instances button.

image by author

Now you can see a screen like below and click the select button on Amazon Linux 2 AMI

Now select the Instance type you need. CPU and MEMORY are depending on the instance type. To our application 1 CPU and 1GB, MEMORY is enough. So select t2.micro instance and next click on Configure Instance Details button.

Now you can see the instance summary like the below image and here we are going to change 2 things. The first one is the IAM role and another one is the User Data in the Advance details section.

  1. Change the IAM role

Like the below image click on the IAM role and select the IAM role‘MyEC2CodeDeployRole’ that we previously created.

2. Change the User data in the Advanced Details section. Here we add a script for creating an instance background for installing ruby and get.

#!/bin/bash
sudo yum -y update
sudo yum -y install ruby
sudo yum -y install wget
cd /home/ec2-user
wget https://aws-codedeploy-us-east-1.s3.amazonaws.com/latest/install
sudo chmod +x ./install
sudo ./install auto

paste this script User data section and click on the Next button.

Now you can see a summary like below and click on the Next button.

After that, you will see this screen, and here we can add the instance name. For that click on Add tag button

Give the instance name under the value name key (there are key-value pairs) and click on the Next button.

image by author (5.7)

Now you can see the background like below. Here we need to provide the facility to download files via the internet(port 80) and need to exhaust port(port 3000) to communicate with our node app.

After adding these configurations, we can see like below (Set the source Anywhere to port 3000) and click on Review and Launch.

After that, it will show the summary like below. Next click on the Launch button.

Now you can see a pop-up like below. It will ask to download EC2 instance access private key file(.pem file).

Now click on launch on the below screen.

Now you can see the instance is running successfully.

4. Create application in CodeDeploy

Select the CodeDeploy from AWS Management Console and select the Application section under CodeDeploy.

Now click on create application button. Now you can see like below and under Application name give a name to application and select the EC2/On-premises option in the compute platform field. After clicking on create the application.

Now you can see a created app like below. Now click on Create Deployment Group.

Here you can give the group name and under the service role, we can see IAM users that have permission to CodeDeploy like below. Here I am going to select ‘MyCodeDeployRole’ that I created previously.

On this screen, there are other options also. No need to change the default value of the Deployment type and At the Environment Configuration section need only select the Amazon EC2 instances option and there are some key-value pairs. Under this key-value pair, we need to specify the previously created EC2 instance like below.

Finally, you can see the below options on this page, and here we can put the default values and the only change is to uncheck the Load balancer because we have only one EC2 instance. Next click on the ‘create deployment group’ button.

After successfully creating the deployment group you can see like below.

5. Create pipeline

The below option of the Deploy is the Pipeline section. Choose the Pipelines under pipeline and click on Create pipeline.

Now give pipeline name like below and if you want can customize the pipeline artifact location in the S3 bucket by selecting as Custom location in Artifact store section, otherwise default location is ok. Next click on the Next button.

In this stage, we can link our project with GitHub.

  • As source provider select ‘GitHub (Version 2)’.
  • Next, select your GitHub username (if is this your first time try with Connect to GitHub button, and then your GitHub username will list).
  • After selecting your code repository.
  • Next, select your branch name that wants to sync application changes with CodePipeline.
  • Now click on next.

After that, you can see the below screen and you can skip this step.

Now you can provide those configurations

  • Set the ‘AWS CodeDeploy’ as the Deploy provider
  • Next set the application name that we previously created in the CodeDeploy section.
  • Next, select the Deployment group that we created in the CodeDeploy section.
  • Now click on next.

Now you can see the pipeline summary like below and click on create the pipeline.

Now you can see successful deployment like below.

6. View the deployed app

Now you can go to the EC2 instance section and select the provided instance previously and copy the ‘public IPV4 address’ and try with exhausted port. As an example, 18.117.136.199:3000

Now you can see the application is successfully running on the AWS EC2 instance. Now you can push changes to the pipeline triggering branch and see the changes in the application.

7. Error resolving

For any deployment, you can see the status Deployments section under CodeDeploy. In that section, we cannot find the exact reason to fail the deployment. So that we need to read logs and find bugs.

7.1 Code agent running check

The CodeDeploy agent is a software package that, when installed and configured on an instance, makes it possible for that instance to be used in CodeDeploy deployments. To find bugs connect the AWS instance with the putty client and try to check whether Code Agent is running or not using the below command

sudo service codedeploy-agent status

If not running the code agent you can uninstall it with the below command and retry the deployment.

sudo yum erase codedeploy-agent

7.2 Read app.out.log and app.err.log files in the deployed app folder.

Using putty client you can go to an app-created folder(This folder is created according to shell script files that we wrote in the app script folder) and you can read app.out.log and app.err.log files. If any kind of error it will write in the app.err.log and other normal app logs can view in the app.out.log file. To view this file you can use the ‘cat’ command like below.

In addition to that, you can see the CodeDeploy logs in this location.

/opt/codedeploy-agent/deployment-root/deployment-logs/codedeploy-agent-deployments.log

I hope this article will help you build your own customized CI/CD Pipelines with AWS and help to resolve coming errors.

Happy Deploying>>

--

--