Skip to main content

Command Palette

Search for a command to run...

🚀 Deploying a 3-Tier Architecture Web Application on AWS from Scratch

Updated
6 min read

In this blog post, I will walk you through how to deploy a 3-Tier Architecture Application using AWS services like EC2, S3, RDS, IAM, and more — based on an amazing open-source project by KastroVKiran.
Project GitHub link: https://github.com/KastroVKiran/3TierArchitectureApp

This tutorial will cover:

  • Setting up the 3-tier architecture

  • Deploying the application

  • Best practices

  • Screenshot suggestions for documentation clarity

🏗️ Overview of 3-Tier Architecture

A 3-Tier Architecture consists of:

  • Web Layer: Client-facing (Web Server on EC2)

  • Application Layer: Business logic (Backend Server on EC2)

  • Database Layer: Data storage (RDS MySQL)

Each layer is separated by security groups, and traffic flows from:

  1. Client → Web Server

  2. Web Server → Application Server

  3. Application Server → Database


☁️ AWS Services Used

ComponentAWS Service
Web TierEC2 (Web Server)
App TierEC2 (App Server)
DB TierAmazon RDS (MySQL)
StorageS3 Bucket
NetworkingVPC, Subnets, Internet Gateway, NAT Gateway
SecuritySecurity Groups, IAM Roles/Policies

🛠️ Step-by-Step Deployment Guide

1. Create VPC and Networking Resources

  • Create a new VPC with CIDR block 192.168.0.0/22

  • Select 2 Availability Zones (AZs)

  • Add 4 subnets:

    • 2 public (for Web/App tier)

    • 4 private (2 for App tier and 2 for DB tier)

  • Create and attach an Internet Gateway to the VPC.

  • Add a NAT Gateway for private subnet internet access.

  • Configure Route Tables accordingly.


2. Create 5 Security Groups

  • Create SG for External Application load balancer.

  • Create SG for Web tier (Inbound rule - Open for SG of External ALB and VPC port i.e 192.168.0.0/22 )

  • Create SG for App tier (Inbound rule - Open for 4000 port (React JS application))

  • Create SG for Internal Application load balancer.(Inbound rule - Open for VPC port i.e 192.168.0.0/22 )

  • Create SG for DB

    Note: Whatever resources are running in VPC those are only those resources will communicate with db


3. Set up S3 Bucket

  • Create an S3 bucket to store your application artifacts (e.g., frontend build files).

  • Upload your frontend files here for easy access.


4. Set up IAM Roles and Policies

  • Create IAM Role allowing EC2 instances to access S3.

  • Attach ‘AmazonEC2RoleforSSM‘ IAM policies.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ssm:DescribeAssociation",
                "ssm:GetDeployablePatchSnapshotForInstance",
                "ssm:GetDocument",
                "ssm:DescribeDocument",
                "ssm:GetManifest",
                "ssm:GetParameters",
                "ssm:ListAssociations",
                "ssm:ListInstanceAssociations",
                "ssm:PutInventory",
                "ssm:PutComplianceItems",
                "ssm:PutConfigurePackageResult",
                "ssm:UpdateAssociationStatus",
                "ssm:UpdateInstanceAssociationStatus",
                "ssm:UpdateInstanceInformation"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "ssmmessages:CreateControlChannel",
                "ssmmessages:CreateDataChannel",
                "ssmmessages:OpenControlChannel",
                "ssmmessages:OpenDataChannel"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "ec2messages:AcknowledgeMessage",
                "ec2messages:DeleteMessage",
                "ec2messages:FailMessage",
                "ec2messages:GetEndpoint",
                "ec2messages:GetMessages",
                "ec2messages:SendReply"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "cloudwatch:PutMetricData"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "ec2:DescribeInstanceStatus"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "ds:CreateComputer",
                "ds:DescribeDirectories"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:DescribeLogGroups",
                "logs:DescribeLogStreams",
                "logs:PutLogEvents"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetBucketLocation",
                "s3:PutObject",
                "s3:GetObject",
                "s3:GetEncryptionConfiguration",
                "s3:AbortMultipartUpload",
                "s3:ListMultipartUploadParts",
                "s3:ListBucket",
                "s3:ListBucketMultipartUploads"
            ],
            "Resource": "*"
        }
    ]
}


5. Launch Aurora and RDS (MySQL)

  • Create a subnet groups

  • Create MySQL Database

  • Ensure RDS is not publicly accessible.

  • Configure parameter groups for proper networking.


6. Create EC2 Instance for App Server in the private subnet

  1. Launch App Server EC2 Instance with SSH manager

    • Connect with Session manager

  • Install necessary packages (e.g. mysql, nodejs, npm).

    sudo yum install mysql -y

  • Configure MySQL Database: Connect to your MySQL database using the RDS endpoint and your credentials.

    mysql -h <DB_EndPoint> -u admin -p

    Enter password when prompted (e.g., rushi123)

  • Create and verify Database

    CREATE DATABASE webappdb;

  • Switch to the new database:

    USE webappdb;

  • Create the Transactions Table

      CREATE TABLE IF NOT EXISTS transactions (
        id INT NOT NULL AUTO_INCREMENT, 
        amount DECIMAL(10,2), 
        description VARCHAR(100), 
        PRIMARY KEY(id)
      )
    
  • Verify the table

    SHOW TABLES;

  • Insert Sample Data

    INSERT INTO transactions (amount, description) VALUES ('400', 'groceries');

  • Check if the data is inserted

    SELECT * FROM transactions;

  • To exit the MySQL session:

    exit

  • Update Application Configuration and upload in S3 bucket

    Edit the DbConfig.js file with your database credentials.

  • Install and Configure Node.js and PM2

    curl -o- https://raw.githubusercontent.com/avizway1/aws_3tier_architecture/main/install.sh | bash source ~/.bashrc

    nvm install 16

    nvm use 16 (You will see 'Now using node v16.20.2)

    Note:
    NVM stands for Node Version Manager — it helps manage multiple Node.js versions easily.

  • Install PM2 (Node.js process manager)

    npm install -g pm2

  • Download Application Code from S3 and Start the App

    • Go to home directory: cd ~/

    • Copy the app code from your S3 bucket:

      sudo aws s3 cp s3:///application-code/app-tier/ app-tier --recursive

    • List files: ls

    • Navigate into the application folder: cd app-tier/

    • Install dependencies: npm install

    • Start the app: pm2 start index.js

    • Check the app status: pm2 list or pm2 status

  • To verify logs: pm2 logs

  • Configure PM2 to Auto-Start on Reboot

    pm2 startup

    pm2 save


  1. Create target group

  2. Create load balance

    1. Open ‘nginx.conf’ file and update location /api/ with load balancer name

  1. Now update in S3 bucket

7. Launch EC2 Instances for Web Server in the private subnet

  • Launch EC2 Instances for Web Server in the public subnet

  • Connect with Session manager and follow the commands which we used for App Server

      sudo -su ec2-user (To work as an ec2-user)    
    
      cd /home/ec2-user
    
      curl -o- https://raw.githubusercontent.com/avizway1/aws_3tier_architecture/main/install.sh | bash
      source ~/.bashrc
      nvm install 16
      nvm use 16
    
      aws s3 cp s3://<S3 Bucker Name>/application-code/web-tier/ web-tier --recursive
      Ex: aws s3 cp s3://demo-3tier-project/application-code/web-tier/ web-tier --recursive
    
      ls ----> You will see 'web-tier'
    
      cd web-tier
      npm install
      npm run build
    
      aws s3 cp s3://<S3 Bucker Name>/application-code/web-tier/ web-tier --recursive
    
      ls ----> You will see 'web-tier'
    

  • Install dependencies: npm install

  • Troubleshoot : If you are getting above error then give permission to web-tier and run npm install
    sudo chown -R ec2-user:ec2-user /home/ec2-user/web-tier

  • Run : npm run build

  • Install nginx:

    sudo amazon-linux-extras install nginx1 -y

  • Update Nginx configuration and restart the service

    cd /etc/nginx (Your are in nginx path)

    ls

    sudo rm nginx.conf

    sudo aws s3 cp s3:///application-code/nginx.conf

  • Restrt the mginx service

    sudo service nginx restart

  • Give RW permission to

    chmod -R 755 /home/ec2-user

  • Turn on nginx

    sudo chkconfig nginx on

  • To check the output of the App:

    We can check using the Web-Tier-Instance public IP.

    But before checking lets open port no 80.


✅ Final Check

  • Test your Application from the public DNS of Web EC2.

  • Application should flow: Frontend → Backend → Database.

  • Add data

  • Delete data


🧹 Clean Up

After verifying everything:

  • Terminate EC2 instances

  • Delete RDS instance

  • Delete S3 bucket

  • Delete VPC and networking resources\