DEV Community

Cover image for Deploying Node.js Application on AWS EC2: The Essential Guide.
Emmanuel Eneche
Emmanuel Eneche

Posted on • Updated on

Deploying Node.js Application on AWS EC2: The Essential Guide.

Introduction

After building your application, you will definitely be required to deploy that application to an online server in order to make it available for everyone to see, especially your target audience, users, or customers. Hence, The goal is to take the running application from your local machine and have it installed on a cloud server/host to enable accessibility of your application. Today, we'll do a deep dive into deploying your code to AWS EC2.

Importance of Deploying to AWS EC2

One key importance of deploying code to a cloud infrastructure like AWS is Security. Security is the uppermost priority for any company that is data-driven. AWS makes available a highly secure infrastructure to ensure the privacy of your data. Security infrastructure at AWS follow different layers of data surveillance which include:

❇️ Data protection
❇️ Identity and access management
❇️ Infrastructure protection
❇️ Threat detection and continuous monitoring
❇️ Compliance and data privacy

It is an end-to-end approach so that companies need not worry about their confidentiality, and instead, they can focus on business development. To flow with this article, the following requirements are needed.

What You Need to Proceed

✅ An AWS account
✅ Github account

⏭️ Login to AWS
To start with, you are required to create a free AWS account if you don't have one already, you can register here. After account creation was successful, you can login here as root user by providing your email on the screen as seen below:

AWS-login-screen

On successful login, you will be re-directed to the console.
Click on EC2 as seen below:

create new EC2

OR

At the top left corner, click on Services and on the pop up display click Compute then EC2 as seen below:

AWS EC2 Navigation

⏭️ Seting up a New Instance

Click on the Launch instance button as seen below:

Launch-instance-button

Next, we need to provide the name of the instance as I have called it ec2-tutorial, then select Ubuntu as Operating System as seen below:

EC2 setup1

⏭️ Create key pair

We need to create a key pair. You can use a key pair to securely connect to your instance. Ensure that you have access to the selected key pair before launching the instance.

EC2 setup2

Next, provide a name for the keypair. I filled ec2-tutorial and then hit Create key pair button as seen below. Please take note of the location keypair is saved to.

EC2 setup3

⏭️ Network setting

Tick all three boxes as seen below:

  • Allow SSH Traffic: This allows you to connect to the instance using SSH
  • Allow HTTP Traffic from Internet: This allows you to access the instance from the browser over HTTP (unsecure connection)
  • Allow HTTPS Traffic from Internet: This allows you to access the instance from the browser over HTTPS (secure connection)

ec2 setup4

⏭️ Summary of Instance (Before launch)

The settings provided above is only the minimum requirement needed to spin up the EC2 instance. You can proceed by clicking the launch instance button on the right as seen below:

ec2 setup5

✅ Success
We have created a new instance successfully. You can click on the Instances > tab highlighted in black to view your running instance.

ec2 setup6

Now, click on the instance ID to view details as highlighted below:

ec2 setup7

⏭️ Configure an Elastic IP

In order to avoid connectivity issues and loss of IP address whenever the server is switched off or in maintenance mode, we would allocate an Elastic IP to the Instance. On left side menu under Network & Security, click on Elastic IPs following the highlighted mark as seen below:

ec2 setup8

On the Elastic IP Addresses page, click on Allocate Elastic IP Address following the Highlighted area as seen below:

ec2 setup8

⏭️ On the Allocate Elastic IP address page, since we've got only 1 default network group, it has been selected by default. You can leave the fields default as it is and click on Allocate as seen below:

ec2 setup9

We have allocated an Elastic IP to our account. We will click on the check box to select the Elastic IP, so we can associate the created Elastic IP to our EC2, as seen below:

ec2 setup10

⏭️ Click on Associate Elastic IP address option as seen below:
ec2 setup11

⏭️ On the Associate Elastic IP info page, do the following:

  • In the instance field, select the instance we created earlier and
  • Click the Associate button as seen below:

ec2 setup12

✅ Success
Elastic IP was associated successfully as seen below:
ec2 setup13

When you navigate to the instances page and select the running instance, you will see the Elastic IP address now active, as seen in the highlighted area below:

ec2 setup14

⏭️ Connecting the EC2 Instance via Terminal

Still on the instances pages, click connect at the top
ec2 setup15

You will be redirected to the Connect to Instance page. Copy the SSH command as highlighted below:

ec2 setup16
Connect to instance section

⏭️ Granting Access to the Key Pair file

We need to locate the key pair file downloaded earlier and ensure it is not publicly accessible. Head over to your terminal and run the following commands;

cd Downloads
Enter fullscreen mode Exit fullscreen mode

ec2 setup17

On your terminal, still on the Download path, run the following commands;

 sudo chmod 400 "ec2-tutorial.pem"
Enter fullscreen mode Exit fullscreen mode

✅ Done. The key pair file is now ready for use.

⏭️ Copy and paste the SSH command you saw in the highlighted area of Connect To Instance section above, on your terminal to initiate a connection to your EC2 instance by doing this;

ssh -i "ec2-tutorial.pem" ubuntu@ec2-54-167-228-166.compute-1.amazonaws.com
Enter fullscreen mode Exit fullscreen mode

When prompted with "Are you sure you want to connect?" type "yes" to continue, as seen below:

ec2 setup18

Connection Success

We have now connected successfully into our EC2 instance as seen here:

ec2 setup19

⏭️ Installing Node.js

We'll be installing Node.js with Apt, using Nodesource PPA.
Since this is our first interaction with the apt packaging system in this session, we will update our local package index so that we have access to the most recent package listings, afterwards, we'll get the node.js package. On your EC2 terminal, run the following commands:

sudo apt update
curl -sL https://deb.nodesource.com/setup_20.x -o nodesource_setup.sh
Enter fullscreen mode Exit fullscreen mode

This installs the PPA and to enable us get access to the packages. CURL was used to retrieve the installation script, for your preferred version. To add the nodejs configuration file run the following commands:

sudo bash nodesource_setup.sh
Enter fullscreen mode Exit fullscreen mode

Next, we install Node.js using the command below:

sudo apt-get install nodejs -y
Enter fullscreen mode Exit fullscreen mode

Verify that you’ve installed version 20.x by running node with the -v version flag:

node -v
Enter fullscreen mode Exit fullscreen mode

Output
node setup 1

Node.js Installation Success

Please note that the NodeSource nodejs package contains both the node binary and npm, so you don’t need to install npm separately.

At this point you have successfully installed Node.js and npm using apt and the NodeSource PPA. For more details on installing Node.js, read here.

⏭️ Installing NGINX Web Server

Nginx is a high-performance, open-source web server. It is also commonly used as a reverse proxy server, load balancer, and HTTP cache. Nginx is known for its efficiency, scalability, and low resource consumption, thus making it a popular choice for serving static content, handling high traffic volumes, and improving the performance of web applications.

Nginx is available in Ubuntu’s default repositories. Hence, it is possible to install it from these repositories using the apt packaging system, by running the command:

sudo apt install nginx -y
Enter fullscreen mode Exit fullscreen mode

⏭️ Adjusting the firewall

Before testing Nginx, the firewall software needs to be configured to allow access to the service. Nginx registers itself as a service with ufw upon installation, making it straightforward to allow Nginx access.

Now, We need to enable traffic on all ports by running the following command:

 sudo ufw allow 'Nginx HTTP'
 sudo ufw allow 'Nginx HTTPS'
 sudo ufw allow 'Nginx Full'
 sudo ufw allow 'OpenSSH'
Enter fullscreen mode Exit fullscreen mode

Next, enable ufw with this command:

 sudo ufw enable
Enter fullscreen mode Exit fullscreen mode

To view firewall status, run this command:

sudo ufw status
Enter fullscreen mode Exit fullscreen mode

Output
nginx config

⏭️ Checking Your Web Server

At the end of the installation process, Ubuntu 22.04 starts Nginx. The web server should already be up and running.

We can check the system status to make sure the service is running by typing:

 systemctl status nginx
Enter fullscreen mode Exit fullscreen mode

Output:
nginx config

Head over to your browser and type in your IP address, in my case it is: http://54.167.228.166/

Output:
nginx config

for more on nginx config and commands, read here.

⏭️ Adjusting Nginx Server Blocks

We need to modify the Nginx default configuration file to suit our application needs, by doing the following:

🎯 Create a new directory called Backend in the root of Nginx
🎯 Specify the entry point of our application.
🎯 Adjust the proxy locations according to PORT 8000 (Or any suitable port you prefer).

To create a new dirctory, navigate to /var/www on your terminal and run this command:

nginx config

Then create the 'backend' directory

sudo mkdir backend
Enter fullscreen mode Exit fullscreen mode

Grant access to the backend directory to make it accessible, type:

sudo chmod 755 backend/
Enter fullscreen mode Exit fullscreen mode

To specify the entry point of our application update the Nginx default config by running:

sudo nano /etc/nginx/sites-available/default
Enter fullscreen mode Exit fullscreen mode

Output:
nginx config

Modify the first server block by specifying the entry point of your application, same as the highlighted area below:

config file

⏭️ Adjust PORT 8000
Under the location block, adjust your file to look like below:

location config

To exit shell, run the command:

control + x
Then hit y when prompted to save changes
Enter fullscreen mode Exit fullscreen mode

We need to confirm that the configurations were successful, by running this command:

sudo nginx -t
Enter fullscreen mode Exit fullscreen mode

Output:
nginx config

**Make sure to restart the nginx server after completing these configurations. Type:

sudo systemctl restart nginx
Enter fullscreen mode Exit fullscreen mode

⏭️ Pull Code From Git Repository

We need to pull code from git into the backend folder we created earlier. The code we'll be using for this demo can be found in this repo.

We already setup the project in my last article, read here, and I'll use it mainly for this purpose. You can skip this section and use your existing Node.js project, if you so wish.

In the terminal of your EC2 instance, we'll navigate to the backend folder by running this command:

cd /var/www/backend
Enter fullscreen mode Exit fullscreen mode

git deploy

We must ensure the backend folder is empty, by running the following command:

sudo rm -rf *
Enter fullscreen mode Exit fullscreen mode

Next, we'll clone the git repo by running the command below:

sudo git clone https://github.com/emmabase/Node-TypeScript-project.git .
Enter fullscreen mode Exit fullscreen mode

The " . " tells git to extract only the content of the repo and not creating a new folder. We'll then get this result:

git cloning

We can view the content of the backend folder by using the command:

ls
Enter fullscreen mode Exit fullscreen mode

Output:
git config

Since the project uses TypeScript, we'll install TypeScript globally by running the command below:

 sudo npm install -g typescript
Enter fullscreen mode Exit fullscreen mode

Let's create the .env file inside the backend directory using the command:

sudo touch .env
Enter fullscreen mode Exit fullscreen mode

Then, open the .env by running:

sudo nano .env
Enter fullscreen mode Exit fullscreen mode

Then, paste the following:

APP_URL=http://localhost:8000
MONGO_DB_URL=mongodb://localhost:27017/jwt-tutorial
PORT=8000
Enter fullscreen mode Exit fullscreen mode

Within /var/www/backend, we install all dependencies in the package.json file to prevent errors, by running:

npm i
Enter fullscreen mode Exit fullscreen mode

At this point, all dependencies have been installed, and we can view the contents of the backend folder as seen below:

node config

**Don't forget to grant access to the backend folder to enable read and write access by running the command:

sudo chmod 0777 backend/
Enter fullscreen mode Exit fullscreen mode

Next, we'll navigate to /var/www/backend and compile all TypeScript files which will create the dist/ folder by running the command:

 tsc -w
Enter fullscreen mode Exit fullscreen mode

Output:
Typescript config

⏭️ Installing PM2
We need to start and keep the server running even when we close the terminal. We'll install PM2 globally by running the command:

sudo npm install pm2 -g
Enter fullscreen mode Exit fullscreen mode

Next, we initialize PM2 to generate the ecosystem.config.js to configure our application. Please note ** If you are creating your own configuration file, make sure it ends with .config.js so PM2 is able to recognize it as a configuration file. .To achieve this, run the command:

pm2 init simple
Enter fullscreen mode Exit fullscreen mode

Output:
pm2 config

By running the command ls -a, we see the ecosystem.config.js here:

pm2 config

⏭️ Open the ecosystem.config.js file and change the name and script values with following command:

sudo nano ecosystem.config.js
Enter fullscreen mode Exit fullscreen mode

The default content of this file looks like this:

module.exports = {
  apps : [{
    name   : "app1",
    script : "./app.js"
  }]
}
Enter fullscreen mode Exit fullscreen mode

We'll change it to:

module.exports = {
  apps : [{
    name   : "ec2-tutorial",
    script : "dist/app.js"
  }]
}
Enter fullscreen mode Exit fullscreen mode

Then exit the shell with ctrl + x and press y when prompted to save and hit the Enter key to save and exit.

Finally, to start the application, use the command:

pm2 start 
Enter fullscreen mode Exit fullscreen mode

Output:
pm2 config

Application Started Successfully

Great Job!! Our application is now up and running. We can look at the log by using the pm2 command:

pm2 log
Enter fullscreen mode Exit fullscreen mode

For more on pm2 commands, read details here

Finally, to test our application, head over to the browser and type:

http://54.167.228.166/api/v1/users
Enter fullscreen mode Exit fullscreen mode

Output:
nginx final

🍕 Congratulations, You made it this far. 🕺

Conclusion
So far so good, we have reflected on the key importance of using cloud services like AWS EC2 for deploying and managing code due to top notch security and scalability allowing us focus on business development for customers.

We also journeyed through several services like Nginx web server which is the high-performance and open-source web server and PM2 to help start and keep the application running regardless. In my next article, I'll be taking you thru installing SSL on your application using Let's Encrypt, to serve your application on a HTTPS secure domain.

I encourage you to explore other AWS services and other best practices to manage and scale your application.

I will love to see your comments in the comment section if you enjoyed this piece and also don't forget to like and follow 😊
Also, you can follow me on linkedin via Emmanuel Eneche for more posts like this. See you soon 👋

Top comments (2)

Collapse
 
gbengacode profile image
Gbengacode

Great post

Collapse
 
emmabase profile image
Emmanuel Eneche

Thank you 🙏