Categoriesawsdeployment

MERN application deployment on AWS ( ec2 instance )

This tutorial will guide you on how you can deploy your MERN application on AWS ( ec2 instance ) with the step by step instructions.

  1. AWS instance creation
  2. Connection with ec2 instance by ssh
  3. nvm, Nginx, and default HTML page setup to confirm everything is working according to our expectation
  4. Steps to change the default Nginx config file for MERN application
  5. Procedure to clone project repo
  6. Running Demo

You can download the sample MERN application to learn the concept. later on, you can deploy your own project

Download Link

How you can create an instance in AWS?

Step -1

Open ec2 service and on the left side there is an instances section, click on it

aws ec2 instances block

Step-2

Click on the launch instance button

to create new instance in aws

Step-3

Enter name, select amazon Linux, key pair ( make sure your key-pair name should be the same name as your username otherwise you would face a problem), and then allow traffic from all sources ( SSH, HTTP, HTTPS ).

allow traffic from all sources during creation of the ec2 instance

Step-4

launch the instance and wait 2-5 minutes for proper completion

How to connect with ec2 instance by ssh

First select instance and then click on connect button at the top of the table

ec2 instance connect button to go into the connection page

After redirecting to the connection page, select the ssh tab and follow all the steps which are mentioned. (step-3 and the example are important to connect your terminal with the instance ) but if you are using Windows you can connect with the ec2 instance by putty.

Environment setup to run MERN application on AWS ( ec2 instance )

download nvm to install the node

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
. ~/.nvm/nvm.sh
nvm install 16.13.0 
nvm use 16.13.0

download nginx

sudo amazon-linux-extras install nginx1

in order to check whether Nginx is working or not, do the following steps

When the Nginx service is stopped, you will get the following message:

curl localhost:80

if your nginx is not working then you will see the following error

[root@ip-ADDRESS ec2-user]#  curl localhost:80
curl: (7) Failed to connect to localhost port 80 after 0 ms: Connection refused

So, let’s start the Nginx service:

sudo service nginx start

and then type

curl localhost:80

You will get an HTML page

You can also see the HTML page by visiting the public ipaddress of your ec2 instance

If you are not seeing the html page then you need to allow port 80 in your security group.

-> visit ec2 -> select instance -> on the bottom -> select security -> scroll down -> click on group name -> scroll and then click on edit inbound rule -> allow http and https both

Still, if you are facing the problem, recreate your instance with the following settings

create a new security group -> allow HTTP, HTTPS, and ssh

Steps to change the default Nginx config file to deploy the MERN application

First, open the config file by entering the following command

sudo nano /etc/nginx/nginx.conf 

and paste the following code in the config file and change the port number according to your used port number. I am using 3000 for frontend and 8000 for the backend

location /api {
    rewrite /api/(.*) /$1 break;     
   proxy_pass http://localhost:8000;
        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;
    }

location /{
        proxy_pass http://localhost:3000;
        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;
    }

complete Nginx config code to deploy the MERN application

# For more information on configuration, see:
#   * Official English Documentation: http://nginx.org/en/docs/
#   * Official Russian Documentation: http://nginx.org/ru/docs/

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 4096;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /etc/nginx/conf.d/*.conf;

    server {
        listen       80;
        listen       [::]:80;
        server_name  _;
        root         /usr/share/nginx/html;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;
location /api {
    rewrite /api/(.*) /$1 break;     
   proxy_pass http://localhost:8000;
        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;
    }

location /{
        proxy_pass http://localhost:3000;
        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;
    }
        error_page 404 /404.html;
        #location = /404.html {
        #}

        error_page 500 502 503 504 /50x.html;
        #location = /50x.html {
        #}##
    }

# Settings for a TLS enabled server.
#
#    server {
#        listen       443 ssl http2;
#        listen       [::]:443 ssl http2;
#        server_name  _;
#        root         /usr/share/nginx/html;
#
#        ssl_certificate "/etc/pki/nginx/server.crt";
#        ssl_certificate_key "/etc/pki/nginx/private/server.key";
#        ssl_session_cache shared:SSL:1m;
#        ssl_session_timeout  10m;
#        ssl_ciphers PROFILE=SYSTEM;
#        ssl_prefer_server_ciphers on;
#
#        # Load configuration files for the default server block.
#        include /etc/nginx/default.d/*.conf;
#
#        error_page 404 /404.html;
#            location = /40x.html {
#        }
#
#        error_page 500 502 503 504 /50x.html;
#            location = /50x.html {
#        }
#    }

}

reload your Nginx

sudo systemctl reload nginx

after it, when you will visit your public ip address then you will see 502 bad gateway error, it’s mean everything is ready now we need to run our frontend and backend application

Procedure to clone project repo

sudo yum install git

if your repo is public then you only need to run the git clone command but if your repo is private do the following steps

generate ssh key

ssh-keygen -t ed25519 -C "your_email@example.com"

go to your .ssh folder

cd ~/.ssh

now copy your id_ed25519.pub by running the following command

cat id_ed25519.pub

add this to your github account

visit your github profile -> go to settings by clicking on the top right corner of your profile -> select ssh and GPG keys -> click on new ssh key button -> paste the public key on the description box and you can add any name

Now clone your repo by ssh URL

go to your frontend and install all the packages but if you find an error in installing the packages then do the following steps

first way

sudo npm install

second way

chmod -R 777 yourreponame
npm i

Now we will install pm2

You can further read about pm2

npm i pm2 -g

after it adds the following config in your frontend folder, push it to your GitHub repo and then run the git pull origin master command so you can pull the latest changes in your ec2 server

app.config.json

{
  "apps": [
    {
      "name": "react-app",
      "script": "npx",
      "interpreter": "none",
      "args": "serve -s build -p 3000"
    }
  ]
}

add the following command in your package.json file

 "start:production": "npm run build && pm2 delete app.config.json && pm2 start app.config.json"

after pulling the latest changes in your ec2 server then run the following command to run your frontend but before this make sure your react app knows your latest backend URL and your latest backend URL will be like /api

npm run start:production

for this, I will suggest your code must get the URL from the env file and you only need to update your env file to update the backend URL

you can create an env file in your frontend folder or backend folder like

nano .env

paste your .env variables in your env file and then press

control X   
press y 
press enter

it will create your .env file

npm run start:production

if you want to check whether your react app is working or not then run the following commands

pm2 logs 

Similarly, we will run the node app

First, copy the following app.config.json code in your node project and push the latest changes in your github repo and then pull it in your ec2 instance

{
  "apps": [
    {
      "name": "node-app",
      "script": "index.js",
      "watch": true,
      "env": {
        "NODE_ENV": "production"
      }
    }
  ]
}

add the following command in your package.json file

    "start:production": "pm2 delete app.config.json && pm2 start app.config.json"

if you want to check whether your node app is working or not then run the following commands

pm2 logs 

Running Demo

now you can visit the public ipaddress again and you will see your website

In the next upcoming lecture, I will show you how you can assign a domain and encrypt your domain properly. I will also write an article on how you can create a pipeline so you don’t need to do these steps again and again instead of it you only need to push the code into your repo and everything will occur automatically.

if you like my article, connect me on LinkedIn and share it with your friends😊

Thanks