🚀 Deploying a 3-Tier Architecture Web Application on AWS from Scratch
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:
Client → Web Server
Web Server → Application Server
Application Server → Database

☁️ AWS Services Used
| Component | AWS Service |
| Web Tier | EC2 (Web Server) |
| App Tier | EC2 (App Server) |
| DB Tier | Amazon RDS (MySQL) |
| Storage | S3 Bucket |
| Networking | VPC, Subnets, Internet Gateway, NAT Gateway |
| Security | Security 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/22Select 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
Launch App Server EC2 Instance with SSH manager

- Connect with Session manager

Install necessary packages (e.g.
mysql,nodejs,npm).sudo yum install mysql -yConfigure MySQL Database: Connect to your MySQL database using the RDS endpoint and your credentials.
mysql -h <DB_EndPoint> -u admin -pEnter 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:
exitUpdate Application Configuration and upload in S3 bucket
Edit the
DbConfig.jsfile 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 ~/.bashrcnvm install 16nvm 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 pm2Download 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:
lsNavigate 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 startuppm2 save

Check if the application is running: curl http://localhost:4000/health
You should get the response:
This is the health check.
Create target group

Create load balance

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

- 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 -yUpdate Nginx configuration and restart the service
cd /etc/nginx (Your are in nginx path)lssudo rm nginx.confsudo aws s3 cp s3:///application-code/nginx.conf
Restrt the mginx service
sudo service nginx restartGive RW permission to
chmod -R 755 /home/ec2-userTurn on nginx
sudo chkconfig nginx onTo 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\

