Deploying a NodeJS Application on AWS EC2 with Nginx and SSL

Deploying a NodeJS Application on AWS EC2 with Nginx and SSL

Welcome to a comprehensive guide on deploying a Node.js application to an AWS EC2 instance. This tutorial aims to equip you with the knowledge to deploy your application efficiently and securely.

This tutorial is centered on deploying a Node.js application on an EC2 instance running Ubuntu. However, the methods outlined are applicable to deploying any Node.js application or framework.

Prerequisites

  • An AWS Account
  • A domain name
  • An EC2 instance 📎Link

Getting started

Begin by connecting to your EC2 instance. Once connected, execute the following commands to refresh your package listings

sudo apt update && sudo apt upgrade && sudo apt dist-upgrade

Installing Git

To proceed, we must clone the application into our instance, requiring Git installation. Execute the following to install Git

sudo apt install git

To verify the successful installation of Git

git --version

Installing Node.js

To run a Node.js application, setting up a Node.js environment is crucial. Here, I have added two methods for installing Node.js; please use either one to install Node.

Installing through NodeSource

Here’s a step-by-step guide on how to install Node.js using NodeSource. This will install Node.js and npm (Node package manager):

  1. Retrieve the installation script:
curl -fsSL https://deb.nodesource.com/setup_18.x -o nodesource_setup.sh

(Change 16.x to whatever version line you prefer, like 14.x or 18.x.)

Run the script:

sudo bash nodesource_setup.sh

Install Node.js:

sudo apt-get install -y nodejs

2. Installing through NVM

For this purpose, we’re installing NVM (Node Version Manager), which facilitates the management of multiple Node.js versions, allowing for easy switching between them.

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash

source ~/.bashrc

To install a specific Node.js version

nvm install <node-version>

To switch among various Node.js versions

nvm use <node-version>

Cloning the Repository

To successfully clone and launch the application, follow this checklist.

  • Clone the application.
git clone <https-repo-url>
  • Checkout to the updated branch.
git checkout <branch-name>
  • Add .env file.
sudo nano .env
  • Install npm dependency.
npm ci
  • Build the application.
npm run build
  • Execute the application once to ensure it functions correctly (Opt.).
npm start

After cloning the application and ensuring it’s running correctly, proceed to use PM2 to launch it. This approach guarantees that the application remains operational even after closing the terminal.


Installing PM2

PM2 is a tool for managing Node.js applications. It ensures your apps run continuously, restarts them if they crash, and can manage multiple instances for better performance.

Use it by installing with npm

npm i -g pm2

To launch an application with PM2, first move to the application’s root directory using the cd command. Then execute the following command to start the application with PM2.

pm2 start npm --name "appname" -- run "command"

Following are some of the helpful pm2 commands

// List all the applications
pm2 list

// Log a specific application 
pm2 log <id>

// Start, stop, or restart instances
pm2 start <id>
pm2 stop <id>
pm2 restart <id>

// Examples of passing IDs
pm2 log 1               // Logs application with ID 1
pm2 log all             // Logs all applications
pm2 log 1 2 3           // Logs applications with IDs 1, 2, and 3

Having successfully launched the application with PM2, we now need to ensure it’s accessible externally. For this, we’ll utilize Nginx, a web server that serves as a proxy layer, enabling external access to the application.


Installing Nginx

Execute the following command to install Nginx

sudo apt install nginx

It is recommended that you enable the most restrictive profile that will still allow the traffic you’ve configured. Right now, we will only need to allow traffic on port 80.

sudo ufw allow 'Nginx HTTP'

To confirm Nginx has been correctly installed, use the following command.

sudo systemctl status nginx

After successfully installing Nginx, it’s time to configure it. This involves editing Nginx’s configuration files to define how it serves your application to external requests.

navigate to sites-available inside the nginx folder.

cd /etc/nginx/sites-available/

Create a new file named app1.conf and input the following configurations into it. This file will specify how Nginx directs traffic to your application, setting up the necessary proxy settings for external access.

server {    
	listen 80;
    server_name example.com www.example.com; # change the doamin name
    root /var/www/html;
    index index.html index.htm;
    location / {
    	proxy_pass http://127.0.0.1:3000; # change the port
        proxy_read_timeout 60;
        proxy_connect_timeout 60;
        proxy_redirect off; 
        
        # Allow the use of websockets
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;    
    }
}

Now, Create a symbolic link (symlink) in sites-enabled that points to your configuration file in sites-available. This step is crucial for enabling the new settings you've added for your application.

To create the symbolic link, execute the following command:

sudo ln -s /etc/nginx/sites-available/app1.conf /etc/nginx/sites-enabled/

Likewise, you can create multiple .conf files if you're managing multiple applications. Just ensure to modify the server_name and proxy_pass accordingly.

We can test the nginx config by running the following command.

sudo nginx -t

After completing the configuration, restart Nginx to apply the changes by executing the following command.

sudo systemctl restart nginx.service

Configuring the domain name

To configure your domain, log into your DNS service provider’s website and navigate to the DNS settings. Select type as A record. for a subdomain, enter its name, or use @ to point to your main domain under the name field. In the value field, input the public IP address of your EC2 instance. This step directs traffic from your domain to your application hosted on AWS EC2.

Example:

Type Name Value
A dev xx.xx.xx
A www.dev xx.xx.xx

Enabling SSL certificate

After configuring your domain, the next step is to secure your application with an SSL certificate, enabling HTTPS. This is crucial for establishing a secure connection, protecting data exchange between users and your application.

To install Certbot, which is used for obtaining SSL certificates from Let’s Encrypt for your application’s domains, follow these commands

Update your package list to ensure you can install the latest version of Certbot

sudo apt-get update

Install Certbot and its Nginx plugin:

sudo apt install python3-certbot-nginx -y

To obtain an SSL certificate for your domain using Certbot and Let’s Encrypt, execute the following command:

sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

Automating SSL renew

The generated SSL certificate will be valid for 90 days. To ensure the SSL certificate renews automatically every 90 days, we’ll set up a cron job. A cron job is a scheduled task that runs at predetermined times. This automatic renewal process is vital for keeping your SSL certificate up to date, ensuring your website remains secure without manual intervention.

Start by installing cron

sudo apt install cron

After installing cron, it can be activated using the following command

sudo systemctl enable cron

Create a file on the instance to input the renewal commands.

sudo nano ssl_auto_renew.sh

Insert the following commands into the file we created.

echo "Cron job ran on $(date)" 
sudo certbot renew

Grant execution permissions to the file we created.

sudo chmod +x ./ssl_auto_renew.sh

To set up Cron, use the following command.

sudo crontab -e

This command will ask you to select a text editor. Choose nanoas the editor by selecting option 1.

Insert the provided code into the opened file, save it by pressing ctrl + S, and exit by pressing ctrl + X.

0 0 * * * /home/ubuntu/ssl_auto_renew.sh >> /home/ubuntu/cron.log 2>&1
Note: /home/ubuntu is specific for ubuntu if you are using different Linux distribution use pwd to find out the current directory

0 0 * * * specifies that it will execute daily at 12 AM

The path /home/ubuntu/ssl_auto_renew.sh indicates the location of the script to be run.

The segment >> /home/ubuntu/cron.log 2>&1 directs the output to a file named cron.log, with 2>&1 ensuring that both standard output and error logs are captured.

We can check if the cron is executed by examining the cron.log file, which stores the logs.


Conclusion

We’ve come to the end, and I hope your application is up and running. Thank you for visiting my blog.