Decoupling Highly Available, Scalable Web Application on AWS

In this guide, we'll walk through building a scalable and highly available web application using AWS services. You'll learn how to deploy a monolithic app, decouple it into separate tiers using EC2 and RDS, and scale it with Load Balancer and Auto Scaling.
Note: Security groups and subnet configurations are omitted for clarity. Ensure proper network and IAM configurations in production, use the cloud9 IDE for easier integrations and adaptability.
The architecture overview
We’ll have functional web application and database that works on a single virtual machine then decouple it into RDS for the database and a VM for the web application.
Creating the single VM which have both database and web application buy provisioning an ubuntu ec2 and using this User data script
#!/bin/bash -xe
apt update -y
apt install nodejs unzip wget npm mysql-server -y
#wget https://aws-tc-largeobjects.s3.us-west-2.amazonaws.com/CUR-TF-200-ACCAP1-1-DEV/code.zip -P /home/ubuntu
wget https://aws-tc-largeobjects.s3.us-west-2.amazonaws.com/CUR-TF-200-ACCAP1-1-91571/1-lab-capstone-project-1/code.zip -P /home/ubuntu
cd /home/ubuntu
unzip code.zip -x "resources/codebase_partner/node_modules/*"
cd resources/codebase_partner
npm install aws aws-sdk
mysql -u root -e "CREATE USER 'nodeapp' IDENTIFIED WITH mysql_native_password BY 'student12'";
mysql -u root -e "GRANT all privileges on *.* to 'nodeapp'@'%';"
mysql -u root -e "CREATE DATABASE STUDENTS;"
mysql -u root -e "USE STUDENTS; CREATE TABLE students(
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
address VARCHAR(255) NOT NULL,
city VARCHAR(255) NOT NULL,
state VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL,
phone VARCHAR(100) NOT NULL,
PRIMARY KEY ( id ));"
sed -i 's/.*bind-address.*/bind-address = 0.0.0.0/' /etc/mysql/mysql.conf.d/mysqld.cnf
systemctl enable mysql
service mysql restart
export APP_DB_HOST=$(curl http://169.254.169.254/latest/meta-data/local-ipv4)
export APP_DB_USER=nodeapp
export APP_DB_PASSWORD=student12
export APP_DB_NAME=STUDENTS
export APP_PORT=80
npm start &
echo '#!/bin/bash -xe
cd /home/ubuntu/resources/codebase_partner
export APP_PORT=80
npm start' > /etc/rc.local
chmod +x /etc/rc.local
Test the application by visiting the PublicIP of that VM and enter some data which we will migrate it later on.
Decoupling the application components
Lets separate the database and the web server in infrastructure so that they run independently. The web application should run on a separate virtual machine, and the database should run on MYSQL datbase engine (RDS).
We'll start by creating private subnets in a minimum of two Availability Zones which are the virtual network components that are necessary to support hosting the database.
Then take a dump from mysql by
mysqldump -h <InstancePrivateIP> -u nodeapp -p --databases STUDENTS > data.sql
Now we'll create the rds with mysql engine that will has STUDENTS initial database and username nodeapp with password student12. Note the database Endpoint as we'll use it on the next steps.
Push the mysqldump file that we created previously into the rds by
mysql -h <rds-endpoint> -u nodeapp -p STUDENTS < data.sql
Then enter the rds and check if it is successfully went into it by
mysql -h <rds-endpoint> -u nodeapp -p
USE STUDENTS;
SHOW TABLES;
SELECET * FROM students;
Now for security we'll create secret in the secret manager as the web application which will be on the new instance will use it.
aws secretsmanager create-secret \
--name Mydbsecret \
--description "Database secret for web app" \
--secret-string "{\"user\":\"nodeapp\",\"password\":\"student12\",\"host\":\"<rds-endpoint>\",\"db\":\"STUDENTS\"}"
and make a role to allow the ec2 instances use this secrete. Then we'll create the web application instance attaching the role to it and using the following script in the user data when provisioning it
#!/bin/bash -xe
apt update -y
apt install nodejs unzip wget npm mysql-client -y
#wget https://aws-tc-largeobjects.s3.us-west-2.amazonaws.com/CUR-TF-200-ACCAP1-1-DEV/code.zip -P /home/ubuntu
wget https://aws-tc-largeobjects.s3.us-west-2.amazonaws.com/CUR-TF-200-ACCAP1-1-91571/1-lab-capstone-project-1/code.zip -P /home/ubuntu
cd /home/ubuntu
unzip code.zip -x "resources/codebase_partner/node_modules/*"
cd resources/codebase_partner
npm install aws aws-sdk
export APP_PORT=80
npm start &
echo '#!/bin/bash -xe
cd /home/ubuntu/resources/codebase_partner
export APP_PORT=80
npm start' > /etc/rc.local
chmod +x /etc/rc.local
Finally, we'll implement high availability and scalability by creating a load-balancer and auto-scaling group
First of all, create an image from the new created web application instance which we'll use it to launch identical copies of your server automatically.
Then create a launch template as it tells how to launch the EC2 instances. Create a target group (type:instance) that'll be used by both the auto-scaling group that adds/removes instances and the load-balancer uses this to send traffic to healthy servers.
Lastly, create the load-balancer that have a listener on a port (HTTP 80).
Then visit the DNS name of the load-balancer from your browser.
Subscribe to my newsletter
Read articles from Abdelrhman Kamal directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Abdelrhman Kamal
Abdelrhman Kamal
Cloud Practitioner