Deploying Node.js Application on AWS EC2: The Essential Guide.
Tags: webdev, learning, programming, tutorial
Published: 2024-02-27 06:51:50

## 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](https://portal.aws.amazon.com/billing/signup#/start/email). After account creation was successful, you can [login here](https://signin.aws.amazon.com/signin) as **root user** by providing your email on the screen as seen below:

![AWS-login-screen](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ep48i6t9zm2qpdm6vd0t.png)

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

![create new EC2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pxbox1jbyp5he4fqbaiw.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/50hkku8xu3i36mddhinf.png)

⏭️ **Seting up a New Instance**

Click on the **Launch instance** button as seen below:

![Launch-instance-button](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s7ftjl6crpn1hvupwdni.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tejoyzn2ii1ac1n80t1q.png)

⏭️ **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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0ym184cer72rm7i4sylb.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1yt1tn7jeg9ad1u789uf.png)

⏭️ **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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f03erhr1aklf2qjjmitr.png)

⏭️ **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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z46dj3uou50u0rvq7zxw.png)

✅ 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vlr3f8iytermqk1zk1lg.png)

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

![ec2 setup7](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fu4cqwaof8iolorwaxed.png)

⏭️ **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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kf2ep5wlg9j7ofvbp5dl.png)

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

![ec2 setup8](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lwd0zjxw2wg32cquel9n.png)

⏭️ 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e649ymrjk9hqu1m9f9vp.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r3qthpfvjkf5fq9isf6x.png)

⏭️ Click on Associate Elastic IP address option as seen below:
![ec2 setup11](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a6pj6zlr5clgmowozxka.png)

⏭️ 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bq6tj5xgjwcy0rdu5w2d.png)

✅ Success
Elastic IP was associated successfully as seen below:
![ec2 setup13](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l75j6jssgfjdxlchtfkk.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0xmxevt8kxqp4b9obsgd.png)

⏭️ **Connecting the EC2 Instance via Terminal**

Still on the instances pages, click connect at the top
![ec2 setup15](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4vdwi028r1j63ffb5vh0.png)

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

![ec2 setup16](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s3ge6h96vh5hj674c2hz.png)
_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;

```javascript
cd Downloads
```
![ec2 setup17](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zkyddtkwhtsmh13lim5n.png)

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

```javascript
 sudo chmod 400 "ec2-tutorial.pem"
```
✅ 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;

```javascript
ssh -i "ec2-tutorial.pem" ubuntu@ec2-54-167-228-166.compute-1.amazonaws.com
```
When prompted with "Are you sure you want to connect?" type "yes" to continue, as seen below:
 
![ec2 setup18](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tt9qtxr4k1mmacfee2qr.png)

✅ **Connection Success**

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

![ec2 setup19](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ha81o0zuwvar2kxp1k5q.png)

⏭️ **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:

```javascript
sudo apt update
curl -sL https://deb.nodesource.com/setup_20.x -o nodesource_setup.sh
```
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:

```javascript
sudo bash nodesource_setup.sh
```
Next, we install Node.js using the command below:
```javascript
sudo apt-get install nodejs -y
```
Verify that you’ve installed version 20.x by running node with the -v version flag:

```javascript
node -v
```
Output
![node setup 1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9y4q6f0a0pz8bjse0kt3.png)

✅ **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](https://www.digitalocean.com/community/tutorials/how-to-install-node-js-on-ubuntu-22-04).

⏭️ **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:

```javascript
sudo apt install nginx -y
```
⏭️ **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:

```javascript
 sudo ufw allow 'Nginx HTTP'
 sudo ufw allow 'Nginx HTTPS'
 sudo ufw allow 'Nginx Full'
 sudo ufw allow 'OpenSSH'
```
Next, enable ufw with this command:

```javascript
 sudo ufw enable
```
To view firewall status, run this command:
```javascript
sudo ufw status
```
Output
![nginx config](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/touxmgoqna5vwcf8frtv.png)

⏭️ **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:

```javascript
 systemctl status nginx
```
Output:
![nginx config](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ifa0c74fwbubxxn4ndv2.png)

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

Output:
![nginx config](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xtxqu02c9e2htg60g2ky.png)

for more on nginx config and commands, [read here](https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-ubuntu-22-04).

⏭️ **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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/it59h27z00yjkf71x2bv.png)

Then create the 'backend' directory
```javascript
sudo mkdir backend
``` 
Grant access to the backend directory to make it accessible, type:

```javascript
sudo chmod 755 backend/
```
To specify the entry point of our application update the Nginx default config by running:

```javascript
sudo nano /etc/nginx/sites-available/default
```
Output:
![nginx config](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0kyy0cyswki0vkup2h4e.png)

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

![config file](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vcrb99jm7ag45ynllv1e.png)

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

![location config](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f3t4ujkbeog727deuz5a.png)

To exit shell, run the command:
```
control + x
Then hit y when prompted to save changes
```
We need to confirm that the configurations were successful, by running this command:

```
sudo nginx -t
```
Output:
![nginx config](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c0n4jjvif3bhjnvy0ulx.png)

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

```
sudo systemctl restart nginx
```

⏭️ **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](https://github.com/emmabase/Node-TypeScript-project). 

We already setup the project in my last article, [read here](Enhancing Security in Node.js & TypeScript Applications with JWT Authentication.), 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
```
![git deploy](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0mn52fue3fdin5zk43rd.png)

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

```
sudo rm -rf *
```

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

```
sudo git clone https://github.com/emmabase/Node-TypeScript-project.git .
```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/09hxpe74mqdiiqfrelwa.png)

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

```
ls
```

Output:
![git config](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/klo3za0kkjj7mhhdk8wk.png)

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

```javascript
 sudo npm install -g typescript
``` 

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

```
sudo touch .env
```
Then, open the .env by running:

```
sudo nano .env
```

Then, paste the following:

```
APP_URL=http://localhost:8000
MONGO_DB_URL=mongodb://localhost:27017/jwt-tutorial
PORT=8000
```

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

```
npm i
```

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

![node config](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/120x9v1bmdubt3ti4f21.png)

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

```
sudo chmod 0777 backend/
```

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

```javascript
 tsc -w
```

Output:
![Typescript config](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z0i076low8i33wfdumbj.png)


⏭️ 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
```
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
```
Output:
![pm2 config](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s4j0ltpscvru5150lpb0.png)

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

![pm2 config](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kxvlmq5siwtusorkmird.png)

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

```javascript
sudo nano ecosystem.config.js
```
The default content of this file looks like this:

```javascript
module.exports = {
  apps : [{
    name   : "app1",
    script : "./app.js"
  }]
}
```

We'll change it to:

```javascript
module.exports = {
  apps : [{
    name   : "ec2-tutorial",
    script : "dist/app.js"
  }]
}
```

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 
```
Output:
![pm2 config](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/heycu77wwp5huyrl7zwu.png)

✅ **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
```
For more on pm2 commands, read [details here](https://pm2.keymetrics.io/docs/usage/application-declaration/)

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

```
http://54.167.228.166/api/v1/users
```
Output:
![nginx final](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tu289p2s0htfzvl2uja2.png)

🍕 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](linkedin.com/in/emmanuel-samson-eneche) for more posts like this. See you soon 👋