How I Built a Highly Available Web Application on AWS Using EC2, ALB, and Auto Scaling
Learn how I designed a highly available web application architecture on AWS using Amazon EC2, an Application Load Balancer, Auto Scaling, and Amazon VPC. This project helped me understand how AWS distributes traffic, replaces unhealthy instances, and scales applications automatically.
When I started learning cloud infrastructure, one of the concepts I wanted to understand practically was high availability.
Running a website on a single EC2 instance is simple, but it creates a major problem: what happens if that instance becomes unavailable or receives too much traffic?
To solve this problem, I designed a simple highly available web application architecture using AWS services.
The main services I used were:
Amazon EC2
Application Load Balancer (ALB)
EC2 Auto Scaling
Amazon VPC
Security Groups
Availability Zones
The goal was to create an architecture where traffic could be distributed across multiple servers and unhealthy instances could be replaced automatically.
šļø Architecture
The architecture follows this basic flow:
Internet
ā
ā¼
āāāāāāāāāāāāāāāāāāā
ā Application ā
ā Load Balancer ā
āāāāāāāāāā¬āāāāāāāāā
ā
āāāāāāāāāāā“āāāāāāāāāā
ā¼ ā¼
āāāāāāāāāāāāā āāāāāāāāāāāāā
ā EC2 ā ā EC2 ā
ā Instance 1ā ā Instance 2ā
ā AZ-1 ā ā AZ-2 ā
āāāāāāāāāāāāā āāāāāāāāāāāāā
ā² ā²
āāāāāāāāāāā¬āāāāāāāāāā
ā
Auto Scaling Group
The Application Load Balancer acts as the entry point for users.
Instead of users connecting directly to an EC2 instance, they connect to the load balancer.
The ALB then forwards requests to healthy EC2 instances.
1. Creating the VPC
I started by creating the network infrastructure using Amazon VPC.
The VPC contained multiple subnets distributed across Availability Zones.
For example:
VPC: 10.0.0.0/16
Running a website on a single EC2 instance is simple, but it creates a major problem: what happens if that instance becomes unavailable or receives too much traffic?
To solve this problem, I designed a simple highly available web application architecture using AWS services.
The main services I used were:
Amazon EC2
Application Load Balancer (ALB)
EC2 Auto Scaling
Amazon VPC
Security Groups
Availability Zones
The goal was to create an architecture where traffic could be distributed across multiple servers and unhealthy instances could be replaced automatically.
šļø Architecture
The architecture follows this basic flow:
Internet
ā
ā¼
āāāāāāāāāāāāāāāāāāā
ā Application ā
ā Load Balancer ā
āāāāāāāāāā¬āāāāāāāāā
ā
āāāāāāāāāāā“āāāāāāāāāā
ā¼ ā¼
āāāāāāāāāāāāā āāāāāāāāāāāāā
ā EC2 ā ā EC2 ā
ā Instance 1ā ā Instance 2ā
ā AZ-1 ā ā AZ-2 ā
āāāāāāāāāāāāā āāāāāāāāāāāāā
ā² ā²
āāāāāāāāāāā¬āāāāāāāāāā
ā
Auto Scaling Group
The Application Load Balancer acts as the entry point for users.
Instead of users connecting directly to an EC2 instance, they connect to the load balancer.
The ALB then forwards requests to healthy EC2 instances.
1. Creating the VPC
I started by creating the network infrastructure using Amazon VPC.
The VPC contained multiple subnets distributed across Availability Zones.
For example:
VPC: 10.0.0.0/16
Availability Zone A
āāā Public Subnet: 10.0.1.0/24
āāā Private Subnet: 10.0.2.0/24
āāā Public Subnet: 10.0.1.0/24
āāā Private Subnet: 10.0.2.0/24
Availability Zone B
āāā Public Subnet: 10.0.3.0/24
āāā Private Subnet: 10.0.4.0/24
Using multiple Availability Zones is important because it reduces the risk of having a single point of failure.
2. Launching EC2 Instances
Next, I created EC2 instances that would host the web application.
For a basic Linux web server, I installed Apache and created a simple HTML page.
Example:
sudo apt update
sudo apt install apache2 -y
Then I created a simple website:
sudo nano /var/www/html/index.html
Example:
HTML
<!DOCTYPE html>
<html>
<head>
<title>AWS High Availability</title>
</head>
<body>
<h1>Hello from AWS EC2</h1>
<p>This website is running behind an Application Load Balancer.</p>
</body>
</html>
I also made the pages different on each server so I could identify which instance was responding to a request.
For example:
Server 1 ā "Response from EC2-1"
Server 2 ā "Response from EC2-2"
3. Configuring Security Groups
Security Groups act as virtual firewalls for the resources.
I configured the web servers to accept HTTP traffic from the Application Load Balancer rather than allowing unrestricted traffic directly to the instances.
A simplified configuration is:
ALB Security Group
Inbound:
HTTP 80 ā 0.0.0.0/0
āāā Public Subnet: 10.0.3.0/24
āāā Private Subnet: 10.0.4.0/24
Using multiple Availability Zones is important because it reduces the risk of having a single point of failure.
2. Launching EC2 Instances
Next, I created EC2 instances that would host the web application.
For a basic Linux web server, I installed Apache and created a simple HTML page.
Example:
sudo apt update
sudo apt install apache2 -y
Then I created a simple website:
sudo nano /var/www/html/index.html
Example:
HTML
<!DOCTYPE html>
<html>
<head>
<title>AWS High Availability</title>
</head>
<body>
<h1>Hello from AWS EC2</h1>
<p>This website is running behind an Application Load Balancer.</p>
</body>
</html>
I also made the pages different on each server so I could identify which instance was responding to a request.
For example:
Server 1 ā "Response from EC2-1"
Server 2 ā "Response from EC2-2"
3. Configuring Security Groups
Security Groups act as virtual firewalls for the resources.
I configured the web servers to accept HTTP traffic from the Application Load Balancer rather than allowing unrestricted traffic directly to the instances.
A simplified configuration is:
ALB Security Group
Inbound:
HTTP 80 ā 0.0.0.0/0
EC2 Security Group
Inbound:
HTTP 80 ā ALB Security Group
This is better than simply allowing HTTP traffic from anywhere to the EC2 instances.
It creates a cleaner security boundary:
Internet
ā
ALB
ā
EC2
4. Creating the Application Load Balancer
Next, I created an Application Load Balancer.
The ALB provides a single endpoint for users while distributing incoming requests across multiple backend instances.
I configured:
Listener
HTTP : 80
Target Group
The target group contained my EC2 instances.
Target Group
āāā EC2-1
āāā EC2-2
The ALB continuously performs health checks against the targets.
For example:
Health Check
Protocol: HTTP
Path: /
Port: Traffic Port
If an instance stops responding correctly, the ALB can stop sending traffic to that unhealthy instance.
5. Testing Load Balancing
After configuring the ALB, I accessed the application using the load balancer DNS name.
Instead of connecting directly to:
http://EC2-PUBLIC-IP
I used:
http://ALB-DNS-NAME
The request flow became:
User
ā
ALB
ā
EC2-1 / EC2-2
Refreshing the page allowed me to observe requests being handled by different instances.
This helped me understand load balancing beyond the theory.
6. Adding Auto Scaling
The next step was making the architecture automatically adjust to changing demand.
I created an Auto Scaling Group.
For example:
Minimum capacity: 2
Desired capacity: 2
Maximum capacity: 4
This means:
At least 2 instances should normally be available.
AWS attempts to maintain 2 instances as the desired capacity.
The group can scale up to 4 instances when required.
The Auto Scaling Group also works with the target group used by the Application Load Balancer.
7. What Happens If an Instance Fails?
This was one of the most important concepts I wanted to understand.
Suppose EC2-1 becomes unhealthy.
Without a load balancer:
User ā EC2-1 ā
The application could become unavailable.
With the architecture I built:
ALB
ā
āāāāāāāāā“āāāāāāāā
ā¼ ā¼
EC2-1 ā EC2-2 ā
ā
Response
The ALB can stop routing requests to the unhealthy instance.
Then the Auto Scaling Group can launch a replacement instance to maintain the desired capacity.
This gives the application better resilience.
8. Why Use Multiple Availability Zones?
Deploying instances across different Availability Zones helps reduce dependency on a single infrastructure location.
For example:
Region
ā
āāā AZ-A
ā āāā EC2-1
ā
āāā AZ-B
āāā EC2-2
If there is an issue affecting one Availability Zone, the application can potentially continue serving traffic from resources in another Availability Zone.
This is one of the fundamental principles behind highly available cloud architectures.
š Security Considerations
While building the project, I also learned that availability should not come at the expense of security.
Some important practices include:
Don't expose unnecessary ports.
Use Security Groups to restrict traffic.
Allow users to access the ALB rather than directly exposing backend instances where appropriate.
Use IAM roles instead of storing AWS credentials on EC2.
Use HTTPS/TLS for production applications.
Keep operating systems and applications patched.
Use private subnets for backend resources when the architecture allows it.
š What I Learned
This project helped me connect several AWS concepts together.
Before the project
I understood individual services such as EC2, VPC, and Security Groups.
After the project
I understood how these services work together:
VPC
ā
āāā Subnets
ā
āāā Security Groups
ā
āāā EC2
ā
āāā Application Load Balancer
ā
āāā Auto Scaling
More importantly, I learned that cloud architecture is not simply about launching servers.
It is about designing systems that can handle:
failures
changing traffic
security requirements
availability requirements
operational maintenance
Inbound:
HTTP 80 ā ALB Security Group
This is better than simply allowing HTTP traffic from anywhere to the EC2 instances.
It creates a cleaner security boundary:
Internet
ā
ALB
ā
EC2
4. Creating the Application Load Balancer
Next, I created an Application Load Balancer.
The ALB provides a single endpoint for users while distributing incoming requests across multiple backend instances.
I configured:
Listener
HTTP : 80
Target Group
The target group contained my EC2 instances.
Target Group
āāā EC2-1
āāā EC2-2
The ALB continuously performs health checks against the targets.
For example:
Health Check
Protocol: HTTP
Path: /
Port: Traffic Port
If an instance stops responding correctly, the ALB can stop sending traffic to that unhealthy instance.
5. Testing Load Balancing
After configuring the ALB, I accessed the application using the load balancer DNS name.
Instead of connecting directly to:
http://EC2-PUBLIC-IP
I used:
http://ALB-DNS-NAME
The request flow became:
User
ā
ALB
ā
EC2-1 / EC2-2
Refreshing the page allowed me to observe requests being handled by different instances.
This helped me understand load balancing beyond the theory.
6. Adding Auto Scaling
The next step was making the architecture automatically adjust to changing demand.
I created an Auto Scaling Group.
For example:
Minimum capacity: 2
Desired capacity: 2
Maximum capacity: 4
This means:
At least 2 instances should normally be available.
AWS attempts to maintain 2 instances as the desired capacity.
The group can scale up to 4 instances when required.
The Auto Scaling Group also works with the target group used by the Application Load Balancer.
7. What Happens If an Instance Fails?
This was one of the most important concepts I wanted to understand.
Suppose EC2-1 becomes unhealthy.
Without a load balancer:
User ā EC2-1 ā
The application could become unavailable.
With the architecture I built:
ALB
ā
āāāāāāāāā“āāāāāāāā
ā¼ ā¼
EC2-1 ā EC2-2 ā
ā
Response
The ALB can stop routing requests to the unhealthy instance.
Then the Auto Scaling Group can launch a replacement instance to maintain the desired capacity.
This gives the application better resilience.
8. Why Use Multiple Availability Zones?
Deploying instances across different Availability Zones helps reduce dependency on a single infrastructure location.
For example:
Region
ā
āāā AZ-A
ā āāā EC2-1
ā
āāā AZ-B
āāā EC2-2
If there is an issue affecting one Availability Zone, the application can potentially continue serving traffic from resources in another Availability Zone.
This is one of the fundamental principles behind highly available cloud architectures.
š Security Considerations
While building the project, I also learned that availability should not come at the expense of security.
Some important practices include:
Don't expose unnecessary ports.
Use Security Groups to restrict traffic.
Allow users to access the ALB rather than directly exposing backend instances where appropriate.
Use IAM roles instead of storing AWS credentials on EC2.
Use HTTPS/TLS for production applications.
Keep operating systems and applications patched.
Use private subnets for backend resources when the architecture allows it.
š What I Learned
This project helped me connect several AWS concepts together.
Before the project
I understood individual services such as EC2, VPC, and Security Groups.
After the project
I understood how these services work together:
VPC
ā
āāā Subnets
ā
āāā Security Groups
ā
āāā EC2
ā
āāā Application Load Balancer
ā
āāā Auto Scaling
More importantly, I learned that cloud architecture is not simply about launching servers.
It is about designing systems that can handle:
failures
changing traffic
security requirements
availability requirements
operational maintenance
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article