Build an Auto Scaling Web Tier
Deploy a load-balanced EC2 web tier that scales with HTTP traffic.
Introduction
30 Second Summary
A website can feel fast when one person visits it. A sudden crowd can overwhelm the same server in minutes.
In this project, you will deploy a web tier on AWS behind an Application Load Balancer. You will watch traffic trigger Amazon EC2 Auto Scaling to grow the web tier from one server to two.
What You'll Build
A controlled request stream hits your public Elastic Web Tier page while a second Amazon EC2 instance joins the load balancer's healthy target pool.
By the end of this project, you'll have:
- A public web page that stays reachable through the load balancer while your Auto Scaling group manages its servers.
- A repeatable traffic test that pushes ALBRequestCountPerTarget above its target. You can watch capacity grow from one instance to two.
- Visible load-balancing proof from two targets showing healthy. Your application remains available through the expanded pool.
- Secret Mission: Terminate a live instance. Watch the Auto Scaling group launch a replacement that restores healthy capacity.
What do I need before I start?
You need an AWS account with administrator access.
This project creates usage-based resources that can keep generating charges. The cleanup section shows you how to remove them when you finish.
Before We Start
A clear goal connects every resource you create to the proof you want to see. Before the hands-on work begins, this is your moment to commit to the load-balanced web tier you are about to build.
Prepare the AWS Environment
Your web tier can only accept internet traffic when its Application Load Balancer spans two internet-connected subnets. This step confirms that Amazon VPC foundation before AWS creates the web tier.
The deployment also needs a valid AWS CloudFormation template before it can create a reachable load balancer or install the web server. You will finish with the network checks complete and the template ready to deploy.
In this step, get ready to:
- Confirm that the default VPC has two default public subnets in different Availability Zones.
- Verify that curl is available in AWS CloudShell.
- Build and validate the complete CloudFormation template.
Confirm the default network
A default VPC includes networking that supports a short internet-facing lab. The load balancer also needs subnets in at least two Availability Zones so traffic can reach capacity across separate locations.
- Sign in to the AWS Management Console.
- Choose US East (N. Virginia) from the region selector in the top navigation.
- Use the search bar at the top of the console to open Amazon VPC.
- Choose Your VPCs in the left navigation.
- Check whether the Default VPC column shows Yes.
Choose the tab that matches what you see in the VPC console.
✔️ Default VPC exists
- Select Subnets in the left navigation.
- Find at least two rows where the Default Subnet column shows Yes.
- Confirm that the two rows list different values in the Availability Zone column.
The default network is ready for an Application Load Balancer that spans two Availability Zones.
ⓧ Default VPC is missing
A deleted default VPC can be recreated from the VPC console. AWS also recreates a default subnet in each Availability Zone for the region.
- Return to Your VPCs in the left navigation.
- Choose Actions.
- Choose Create Default VPC.
- Choose Create.
- Select Subnets after creation finishes.
- Confirm that at least two rows show Yes in the Default Subnet column.
- Confirm that those rows list different values in the Availability Zone column.
Default VPC creation did not finish?
Confirm that the console is still set to US East (N. Virginia). An existing default VPC in that region can also prevent another one from being created.
Ask for help with the VPC state:
Good progress. Your AWS account now has the two-AZ network foundation required by the load balancer.
Check curl in AWS CloudShell
The later traffic test uses AWS CloudShell to send repeated HTTP requests without a local AWS CLI installation. CloudShell provides a browser-based Bash environment inside the AWS console.
- Select AWS CloudShell in the console toolbar.
- Wait for the shell prompt to become available.
Before you run the check, what kind of version information do you expect the command to print?
- Check that curl is available by running this command:
curl --version
What does this command check?
The command asks the installed curl program to report its version information. A printed response proves that CloudShell can run the traffic tool needed later.
You should see version information followed by details about the supported features. CloudShell is ready to generate HTTP requests for the scaling test.
No version information?
Confirm that the CloudShell prompt finished loading before entering the command. Refresh the CloudShell session if the browser panel stopped responding.
Get help checking the session:
Build and validate the CloudFormation template
The template describes the entire web tier as infrastructure as code. CloudFormation can use this one artifact to create the same load balancer, compute capacity, health path, and scaling policy together.
- Use the search bar at the top of the AWS Management Console to open AWS CloudFormation.
- Choose Create Stack.
- Choose Build with template studio.
Why CloudFormation here?
A manual console build would spread related settings across several services. CloudFormation keeps the network rules, compute settings, load balancer, and scaling behavior in one reusable template.
That reusable artifact makes every later observation traceable to a declared setting.
- Click inside the Template Studio code editor.
- Select the existing sample text by pressing Cmd+A (macOS) or Ctrl+A (Windows).
- Delete the selected sample text.
- Start auto-scaling-web-tier.yaml by pasting this template metadata and parameter section:
AWSTemplateFormatVersion: '2010-09-09'
Description: Load-balanced EC2 Auto Scaling web tier with request-count target tracking
Parameters:
VpcId:
Description: Default VPC for the lab
Type: AWS::EC2::VPC::Id
PublicSubnetIds:
Description: Two default public subnets in different Availability Zones
Type: List<AWS::EC2::Subnet::Id>
LatestAmiId:
Description: Latest standard x86_64 Amazon Linux 2023 AMI
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64
What do these parameters control?
- The VpcId parameter identifies the default VPC selected during deployment.
- The PublicSubnetIds parameter accepts the two default subnets used by the load balancer and Auto Scaling group.
- The LatestAmiId parameter uses AWS Systems Manager Parameter Store to resolve the latest standard x86_64 Amazon Linux 2023 image.
- Check the opening section by choosing Validate in Template Studio.
You should see confirmation that the current template structure is valid.
Parameter section does not validate?
Compare the spacing beneath each parameter name with the code block. YAML uses indentation to determine which descriptions and types belong to each parameter.
Ask for help checking the parameter indentation:
- Append the load balancer security group section at the bottom of the editor:
Resources:
LoadBalancerSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow HTTP traffic to the Application Load Balancer
VpcId: !Ref VpcId
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
What does this security group do?
The security group allows TCP traffic on port 80 from any IPv4 address. That rule lets browsers reach the internet-facing load balancer over HTTP.
- Check the load balancer rule by choosing Validate.
You should see confirmation that the template remains valid with its first resource.
Security group section does not validate?
Check that Resources begins at the far left. Confirm that the ingress rule is nested beneath SecurityGroupIngress.
Ask for help checking the resource structure:
- Append the instance security group section at the bottom of the editor:
InstanceSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow HTTP traffic only from the load balancer
VpcId: !Ref VpcId
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
SourceSecurityGroupId: !Ref LoadBalancerSecurityGroup
How is instance access restricted?
This security group accepts HTTP traffic only when it comes from LoadBalancerSecurityGroup. The rule keeps direct internet traffic away from the web instances.
- Check the instance rule by choosing Validate.
You should see confirmation that both security group resources are valid.
Instance security group does not validate?
Confirm that InstanceSecurityGroup aligns with LoadBalancerSecurityGroup. Check that the source references the load balancer security group exactly.
Ask for help checking the reference:
- Append the target group section at the bottom of the editor:
WebTargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Port: 80
Protocol: HTTP
TargetType: instance
VpcId: !Ref VpcId
What is the target group for?
The target group represents the EC2 instances that can receive HTTP requests on port 80. The load balancer later checks these registered instances before routing requests to them.
- Check the target group structure by choosing Validate.
You should see confirmation that the target group definition is valid.
Target group section does not validate?
Check that WebTargetGroup is nested under Resources. Confirm that its four properties share the same indentation.
Ask for help checking the target group:
- Append the Application Load Balancer section at the bottom of the editor:
ApplicationLoadBalancer:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Scheme: internet-facing
Type: application
Subnets: !Ref PublicSubnetIds
SecurityGroups:
- !Ref LoadBalancerSecurityGroup
How is the load balancer placed?
The load balancer is internet-facing. It spans the subnets supplied through PublicSubnetIds and uses the public HTTP security group.
- Check the load balancer definition by choosing Validate.
You should see confirmation that the load balancer resource is valid.
Load balancer section does not validate?
Confirm that Subnets references PublicSubnetIds. Check that the security group list contains the load balancer security group reference.
Ask for help checking the load balancer resource:
- Append the HTTP listener section at the bottom of the editor:
WebListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
LoadBalancerArn: !Ref ApplicationLoadBalancer
Port: 80
Protocol: HTTP
DefaultActions:
- Type: forward
TargetGroupArn: !Ref WebTargetGroup
How are requests forwarded?
The listener accepts HTTP requests on port 80. Its default action forwards each request to WebTargetGroup.
- Check the listener definition by choosing Validate.
You should see confirmation that the listener can reference the load balancer and target group.
Listener section does not validate?
Check that DefaultActions contains a list item. Confirm that the references use the exact resource names already in the template.
Ask for help checking the listener:
- Append the launch template settings and startup script at the bottom of the editor:
WebLaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateName: !Sub '${AWS::StackName}-launch-template'
LaunchTemplateData:
ImageId: !Ref LatestAmiId
InstanceType: t3.micro
CreditSpecification:
CpuCredits: standard
SecurityGroupIds:
- !Ref InstanceSecurityGroup
UserData:
Fn::Base64: !Sub |
#!/bin/bash
sudo dnf install -y httpd wget php-fpm php-mysqli php-json php php-devel
sudo systemctl enable httpd
cat > /var/www/html/index.html <<'HTML'
What does the launch template prepare?
- The launch template selects the resolved Amazon Linux 2023 image and the t3.micro instance type.
- The standard CPU credit setting keeps the burstable instance on standard credit behavior.
- The startup script installs Apache and enables it at boot before writing the web page into /var/www/html/index.html.
- Check the launch template structure by choosing Validate.
You should see confirmation that the launch template and startup script structure are valid.
Launch template section does not validate?
Confirm that every startup command is indented beneath the block marker. Check that SecurityGroupIds contains a list item referencing InstanceSecurityGroup.
Ask for help checking the launch template:
- Complete the launch template by appending the web page and Apache start command directly beneath the previous line:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Elastic Web Tier</title>
<style>
body { font-family: system-ui, sans-serif; margin: 0; background: #0f172a; color: #e2e8f0; }
main { max-width: 720px; margin: 12vh auto; padding: 2rem; background: #1e293b; border-radius: 16px; }
h1 { color: #38bdf8; }
code { color: #fbbf24; }
</style>
</head>
<body>
<main>
<h1>Elastic Web Tier</h1>
<p>Your request reached an EC2 instance through an Application Load Balancer.</p>
<p>CloudFormation stack: <code>${AWS::StackName}</code></p>
</main>
</body>
</html>
HTML
sudo systemctl start httpd
What page does each instance serve?
The startup script writes a complete HTML page with the heading Elastic Web Tier. It also inserts the CloudFormation stack name so the browser can prove which deployment produced the page.
The final startup command starts Apache so the instance can answer the target group's HTTP checks.
- Check the completed launch template by choosing Validate.
You should see confirmation that the launch template remains valid with the complete web page.
Web page section does not validate?
Confirm that every HTML line stays aligned beneath the startup script. Check that the closing HTML marker uses the same indentation as the page content.
Ask for help checking the embedded page:
- Append the Auto Scaling group section at the bottom of the editor:
WebAutoScalingGroup:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
LaunchTemplate:
LaunchTemplateId: !Ref WebLaunchTemplate
Version: !GetAtt WebLaunchTemplate.LatestVersionNumber
MinSize: '1'
MaxSize: '2'
DesiredCapacity: '1'
DefaultInstanceWarmup: 30
VPCZoneIdentifier: !Ref PublicSubnetIds
TargetGroupARNs:
- !Ref WebTargetGroup
How is capacity bounded?
The Auto Scaling group starts with one instance and can grow to two. It launches instances across the selected subnets and registers them with WebTargetGroup.
The warmup period gives a new instance time to initialize before its metrics influence another scaling decision.
- Check the Auto Scaling group definition by choosing Validate.
You should see confirmation that the launch template, capacity values, subnets, and target group references are valid.
Auto Scaling group does not validate?
Confirm that the launch template version uses WebLaunchTemplate.LatestVersionNumber. Check that TargetGroupARNs contains the WebTargetGroup reference as a list item.
Ask for help checking the group:
- Append the target-tracking scaling policy section at the bottom of the editor:
RequestCountScalingPolicy:
Type: AWS::AutoScaling::ScalingPolicy
DependsOn: WebListener
Properties:
AutoScalingGroupName: !Ref WebAutoScalingGroup
PolicyType: TargetTrackingScaling
EstimatedInstanceWarmup: 60
TargetTrackingConfiguration:
PredefinedMetricSpecification:
PredefinedMetricType: ALBRequestCountPerTarget
ResourceLabel: !Join
- '/'
- - !GetAtt ApplicationLoadBalancer.LoadBalancerFullName
- !GetAtt WebTargetGroup.TargetGroupFullName
TargetValue: 20
How does request-driven scaling work?
The target-tracking policy watches ALBRequestCountPerTarget. Its target value represents the desired average request count per instance during a one-minute interval.
The resource label joins the full load balancer name with the full target group name. That connection lets the policy scale this specific request path.
- Check the scaling policy definition by choosing Validate.
You should see confirmation that the request-count policy and its dependencies are valid.
Scaling policy does not validate?
Check the nested list beneath ResourceLabel carefully. Confirm that the load balancer and target group attribute names match the resources already declared.
Ask for help checking the policy:
- Complete the template by appending the output section at the bottom of the editor:
Outputs:
ApplicationURL:
Description: Public URL for the load-balanced web page
Value: !Sub 'http://${ApplicationLoadBalancer.DNSName}'
AutoScalingGroupName:
Description: Auto Scaling group to inspect during the lab
Value: !Ref WebAutoScalingGroup
What will these outputs reveal?
- The ApplicationURL output exposes the public HTTP address used to open the web page.
- The AutoScalingGroupName output identifies the group inspected during the scaling tests.
Before you run the final validation, do you expect CloudFormation to accept every reference in the completed template?
- Validate the completed template by choosing Validate in Template Studio.
You should see confirmation that the complete template passes validation. This proves that CloudFormation can parse the parameters, resources, references, and outputs as one template.
Complete template does not validate?
Use the location reported by Template Studio to find the affected section. Compare that section with the matching code block before changing any resource names.
Ask for help with the validation result:
✔️ Awesome, I've got everything!
Your validated template now contains all three parameters, eight resources, and two outputs. Keep Template Studio open for the deployment step.
ⓧ I'd like to double check the full code
Compare the complete contents of auto-scaling-web-tier.yaml with this reference:
AWSTemplateFormatVersion: '2010-09-09'
Description: Load-balanced EC2 Auto Scaling web tier with request-count target tracking
Parameters:
VpcId:
Description: Default VPC for the lab
Type: AWS::EC2::VPC::Id
PublicSubnetIds:
Description: Two default public subnets in different Availability Zones
Type: List<AWS::EC2::Subnet::Id>
LatestAmiId:
Description: Latest standard x86_64 Amazon Linux 2023 AMI
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64
Resources:
LoadBalancerSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow HTTP traffic to the Application Load Balancer
VpcId: !Ref VpcId
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
InstanceSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow HTTP traffic only from the load balancer
VpcId: !Ref VpcId
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
SourceSecurityGroupId: !Ref LoadBalancerSecurityGroup
WebTargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Port: 80
Protocol: HTTP
TargetType: instance
VpcId: !Ref VpcId
ApplicationLoadBalancer:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Scheme: internet-facing
Type: application
Subnets: !Ref PublicSubnetIds
SecurityGroups:
- !Ref LoadBalancerSecurityGroup
WebListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
LoadBalancerArn: !Ref ApplicationLoadBalancer
Port: 80
Protocol: HTTP
DefaultActions:
- Type: forward
TargetGroupArn: !Ref WebTargetGroup
WebLaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateName: !Sub '${AWS::StackName}-launch-template'
LaunchTemplateData:
ImageId: !Ref LatestAmiId
InstanceType: t3.micro
CreditSpecification:
CpuCredits: standard
SecurityGroupIds:
- !Ref InstanceSecurityGroup
UserData:
Fn::Base64: !Sub |
#!/bin/bash
sudo dnf install -y httpd wget php-fpm php-mysqli php-json php php-devel
sudo systemctl enable httpd
cat > /var/www/html/index.html <<'HTML'
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Elastic Web Tier</title>
<style>
body { font-family: system-ui, sans-serif; margin: 0; background: #0f172a; color: #e2e8f0; }
main { max-width: 720px; margin: 12vh auto; padding: 2rem; background: #1e293b; border-radius: 16px; }
h1 { color: #38bdf8; }
code { color: #fbbf24; }
</style>
</head>
<body>
<main>
<h1>Elastic Web Tier</h1>
<p>Your request reached an EC2 instance through an Application Load Balancer.</p>
<p>CloudFormation stack: <code>${AWS::StackName}</code></p>
</main>
</body>
</html>
HTML
sudo systemctl start httpd
WebAutoScalingGroup:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
LaunchTemplate:
LaunchTemplateId: !Ref WebLaunchTemplate
Version: !GetAtt WebLaunchTemplate.LatestVersionNumber
MinSize: '1'
MaxSize: '2'
DesiredCapacity: '1'
DefaultInstanceWarmup: 30
VPCZoneIdentifier: !Ref PublicSubnetIds
TargetGroupARNs:
- !Ref WebTargetGroup
RequestCountScalingPolicy:
Type: AWS::AutoScaling::ScalingPolicy
DependsOn: WebListener
Properties:
AutoScalingGroupName: !Ref WebAutoScalingGroup
PolicyType: TargetTrackingScaling
EstimatedInstanceWarmup: 60
TargetTrackingConfiguration:
PredefinedMetricSpecification:
PredefinedMetricType: ALBRequestCountPerTarget
ResourceLabel: !Join
- '/'
- - !GetAtt ApplicationLoadBalancer.LoadBalancerFullName
- !GetAtt WebTargetGroup.TargetGroupFullName
TargetValue: 20
Outputs:
ApplicationURL:
Description: Public URL for the load-balanced web page
Value: !Sub 'http://${ApplicationLoadBalancer.DNSName}'
AutoScalingGroupName:
Description: Auto Scaling group to inspect during the lab
Value: !Ref WebAutoScalingGroup
What should match?
Resource names, indentation, literal values, and references must match this file exactly. The final validation confirms that the combined YAML forms one valid CloudFormation template.
That is the preparation complete. Your network can support the load balancer, CloudShell can generate traffic, and the validated template is ready to create the first working web tier.
Deploy the Web Tier
Your AWS CloudFormation template passed validation in the previous step. Now it can create the web tier as one stack.
A visible page behind the Application Load Balancer gives you a working baseline before you investigate changing demand. The first version uses one Amazon EC2 instance in an EC2 Auto Scaling group.
In this step, get ready to:
- Configure the stack name plus its default VPC network parameters.
- Submit the CloudFormation stack for deployment.
- Open the live application from the stack outputs.
Configure the stack parameters
CloudFormation parameters connect the reusable template to this AWS environment. The network selections determine where the load balancer can run.
- Return to the validated template in CloudFormation Template Studio.
- Choose Save and continue.
- Enter auto-scaling-web-tier in the Stack name field.
- Select the default VPC you confirmed earlier in the VpcId field.
- Select two default public subnets from different Availability Zones in the PublicSubnetIds field.
- Choose Next.
Why Two Subnets?
An Application Load Balancer uses subnets from at least two Availability Zones. This gives the load balancer more than one location for receiving traffic.
Create the CloudFormation stack
CloudFormation reads the template dependencies before creating each resource. This lets the listener connect to the load balancer while the Auto Scaling group connects to the target group.
Before You Submit
Submitting creates AWS resources that can generate usage-based charges. Cleanup removes the environment as one CloudFormation stack when you finish.
- Leave the optional stack settings unchanged.
- Choose Next.
- Confirm the stack name shows auto-scaling-web-tier.
- Confirm VpcId shows the default VPC you selected.
- Confirm PublicSubnetIds shows two default public subnets from different Availability Zones.
- Keep the standard deployment mode selected.
- Choose Submit.
CloudFormation starts creating the security groups, load balancer, target group, launch template, scaling policy, plus the Auto Scaling group.
Expect the stack to take several minutes while AWS provisions its resources. The Events list changes as CloudFormation works through the template.
- Stay on the Events tab until the stack status reaches CREATE_COMPLETE.
That is the deployment done. Your reusable template is now a live web tier.
Stack Did Not Reach CREATE_COMPLETE?
- Open Events for the stack.
- Locate the earliest resource that reports a failure.
- Read its status reason before retrying the deployment.
Help me diagnose my CloudFormation deployment failure.
Open the live application
Stack outputs expose values generated during deployment. The ApplicationURL output is the public address of your load balancer.
Before you open the URL, what do you expect the page to prove about the path taken by your browser request?
- Open the stack's Outputs tab.
- Confirm the outputs table includes ApplicationURL.
- Confirm the outputs table includes AutoScalingGroupName.
- Choose the value beside ApplicationURL to open it in your browser.
You'll see Elastic Web Tier at the top of the page. You'll also see the stack name auto-scaling-web-tier.
What Does the Live Page Prove?
Your browser sent an HTTP request to the load balancer. The load balancer forwarded that request to the registered instance.
A successful response proves the web server started from the launch template. It also proves the target can receive traffic through the load balancer.
Page Not Loading?
- Return to the stack's Outputs tab.
- Open the ApplicationURL value again.
- Refresh the browser after the instance finishes its initial health checks.
Help me troubleshoot the ApplicationURL.
The web tier is live. Next, you'll test whether a handful of ordinary browser requests is enough to make it grow.
Identify the Scaling Gap
Your Elastic Web Tier is live behind an Application Load Balancer. The first working version is already serving requests.
A working page proves reachability. Elastic capacity needs separate evidence from Amazon EC2 Auto Scaling activity plus the group’s instance count. This step leaves AWS CloudFormation unchanged while you test that behaviour.
In this step, get ready to:
- Locate the Auto Scaling group identified by the stack output.
- Send five ordinary browser requests through ApplicationURL.
- Connect the policy evidence to the unchanged instance count.
Find the Auto Scaling group
The generated group name is easy to lose among the stack resources. The AutoScalingGroupName output gives you the exact group to inspect.
- Return to the AWS CloudFormation console from earlier.
- Select the auto-scaling-web-tier stack.
- Choose the Outputs tab.
- Record the AutoScalingGroupName value here: your Auto Scaling group name.
- Enter Auto Scaling Groups in the AWS Management Console search bar.
- Select Auto Scaling Groups from the search results.
- Select the group whose name matches your Auto Scaling group name.
- Choose the Instance management tab.
You should see one t3.micro instance with lifecycle state InService. You now have a clean baseline before the traffic check.
Can't Find the Group?
- Confirm the console region shows US East (N. Virginia).
- Return to the Outputs tab for auto-scaling-web-tier.
- Compare the selected group name with the AutoScalingGroupName value.
Help me locate my Auto Scaling group
Test five ordinary requests
A target-tracking policy compares observed demand with a configured target. Five browser refreshes give you a small request sample to test against that policy.
Before you refresh, do you think five ordinary page requests will change the group’s instance count?
- Switch back to the browser tab showing the Elastic Web Tier page from earlier.
- Refresh the page five times.
You should see the Elastic Web Tier page load after every refresh. The application remains reachable throughout the test.
- Return to the Auto Scaling group from earlier.
- Choose the Instance management tab.
- Refresh the console page.
You should still see one t3.micro instance with lifecycle state InService. The ordinary requests did not trigger scale-out.
Why Didn't Five Requests Scale?
The ALBRequestCountPerTarget metric measures the average Application Load Balancer request count per Auto Scaling target during a one-minute interval. Your five page loads stayed below the configured target of 20.
The policy kept the desired capacity at 1. This shortfall is the scaling gap you needed to expose.
Page No Longer Loading?
- Return to the stack’s Outputs tab.
- Use the current ApplicationURL value in your browser.
- Confirm the stack still shows CREATE_COMPLETE.
- Confirm the group still has one InService instance.
Help me restore access to the Elastic Web Tier page
Inspect the scaling evidence
The instance count shows the outcome. The activity history shows whether Auto Scaling attempted a capacity change. The policy view shows the demand threshold behind that decision.
- Choose the Activity tab.
- Refresh the console page.
You should see no new scale-out launch activity tied to your five refreshes. The original deployment activity can remain in the history.
- Choose the Automatic scaling tab.
- Locate the target-tracking policy that uses ALBRequestCountPerTarget.
- Confirm the policy’s target value is 20.
Before the final check, how many InService instances should match the evidence you just inspected?
- Choose the Instance management tab.
- Refresh the console page.
You should still see one t3.micro instance with lifecycle state InService. You have now proved that five ordinary requests keep the page reachable without triggering scale-out.
The stack remains CREATE_COMPLETE. Its ApplicationURL and AutoScalingGroupName outputs remain available.
You have identified the scaling gap with visible evidence from the page, policy, activity history, and instance count. Next, you will generate sustained traffic that gives the scaling policy enough demand to add capacity.
Generate Traffic and Scale Out
Your five browser refreshes proved that ApplicationURL stays reachable. They also showed that the Auto Scaling group remains at one InService instance under light traffic.
This time, you will send sustained HTTP traffic from AWS CloudShell. The target-tracking policy will use ALBRequestCountPerTarget to decide when Amazon EC2 Auto Scaling adds capacity.
In this step, get ready to:
- Send three batches of requests to the load balancer.
- Watch the scaling activity complete successfully.
- Confirm that two instances reach the InService lifecycle state.
Generate sustained traffic
A short burst can disappear inside a one-minute metric interval. Three request batches keep demand elevated across several intervals.
This Test Creates Billable Capacity
This test can launch a second t3.micro instance. In US East (N. Virginia), each Linux t3.micro costs $0.0104 per hour.
The load balancer can also continue generating usage-based charges. The cleanup section removes the environment when you finish.
- Return to the auto-scaling-web-tier stack in the AWS CloudFormation console.
- Choose the Outputs tab.
- Copy the ApplicationURL value into this project field: http://your-load-balancer-dns-name.
- Switch back to AWS CloudShell from earlier.
This traffic loop takes a little over three minutes. CloudShell stays mostly quiet while the requests run.
Before you run the test, do you expect sustained requests to produce a different scaling result from five browser refreshes?
- Run the traffic test below after replacing http://your-load-balancer-dns-name with http://your-load-balancer-dns-name:
export LAB_URL='http://your-load-balancer-dns-name'
for minute in 1 2 3; do
for request in {1..100}; do
curl --silent --show-error --output /dev/null "$LAB_URL"
done
sleep 60
done
How Does the Traffic Loop Work?
- The LAB_URL environment variable stores the load balancer URL for the loop.
- The outer loop runs three rounds. The inner loop sends 100 requests during each round.
- The --silent option hides the progress meter. The --output /dev/null option discards each response body.
- The sleep 60 line pauses between request batches so the traffic spans multiple metric intervals.
When the CloudShell prompt returns, all three request batches have finished. The policy now has sustained request data to evaluate against its target value of 20.
Traffic Test Not Completing?
- Check that you replaced the placeholder with the complete ApplicationURL value from the stack outputs.
- Keep the single quotation marks around the URL in the export line.
- Confirm that the Elastic Web Tier page still loads from the same URL in your browser.
Ask for help with the request loop if CloudShell keeps reporting a connection or address problem: Help me troubleshoot my CloudShell traffic test
Watch the scale-out activity
The target-tracking policy evaluates request data through Amazon CloudWatch. The activity history shows whether that policy changed the group's desired capacity.
This part can take several minutes while the new instance launches. The activity may remain in progress while the instance starts.
- Return to the Auto Scaling group from earlier.
- Choose the Activity tab.
Before you refresh, what launch state do you expect to see while the second instance is still starting?
- Refresh the Activity tab until the newest launch activity shows Successful.
You may first see Not yet in service while the instance starts. The later Successful status confirms that the request-count policy triggered a completed scale-out launch.
No New Launch Activity?
- Confirm that the complete traffic loop returned to the CloudShell prompt.
- Check that LAB_URL contains the working ApplicationURL value.
- Wait through another metric interval before refreshing the Activity tab again.
If the group still has no launch entry, use this prompt to inspect the scaling path: Help me diagnose why target tracking did not scale out
Confirm the second instance
A successful activity proves that the launch completed. The instance list proves that the expanded capacity has entered the group's active lifecycle state.
Before you check the instance list, how many InService rows do you expect after the successful launch?
- Choose the Instance management tab.
- Refresh the Instance management tab until two instances show InService.
You should see two t3.micro instances with the InService lifecycle state. The target-tracking action has raised desired capacity from 1 to 2.
That's the scale-out proven. Sustained traffic now produces additional capacity automatically.
Second Instance Still Pending?
- Wait a few more minutes for the instance launch to complete.
- Refresh the Instance management tab again.
- Return to the Activity tab if the launch does not reach Successful.
Use this prompt if the activity succeeds but the second instance does not become active: Help me troubleshoot an instance that is not reaching InService
Your Auto Scaling group now has two active instances. Next, you will confirm that the Application Load Balancer accepts both targets as healthy while the web page stays available.
Verify Healthy Load Balancing
Your request test has already pushed the Amazon EC2 Auto Scaling group to two InService instances. That result proves the target-tracking policy can add capacity.
A second running instance only helps after it passes the target group's health checks. You now need to prove that the Application Load Balancer can keep serving the page through the expanded pool.
In this step, get ready to:
- Follow WebTargetGroup from the deployed stack to its target details.
- Confirm that the expanded HTTP target pool is healthy.
- Reload ApplicationURL to prove that the page remains available.
Follow the target group from the stack
AWS CloudFormation connects each logical resource in the template to the physical AWS resource it created. Following that connection takes you directly to the target pool used by the load balancer.
- Return to the AWS CloudFormation console from earlier.
- Select the auto-scaling-web-tier stack.
- Choose the Resources tab.
- Find WebTargetGroup in the logical resource list.
- Choose the physical ID beside WebTargetGroup.
The target group page identifies the resource attached to the deployed load balancer. This is the pool that receives forwarded application requests.
How the Traffic Path Fits Together
- The internet-facing ApplicationLoadBalancer accepts requests through its HTTP listener on port 80.
- The listener forwards each request to WebTargetGroup.
- WebTargetGroup can route traffic to registered instances after their health checks pass.
Confirm both targets are healthy
The InService lifecycle state confirms that Auto Scaling has placed an instance into service. The healthy target state confirms that the instance can answer the load balancer's health checks.
- Choose the Targets tab.
- Refresh the target list until two registered targets show healthy.
- Confirm that each target uses HTTP port 80.
Strong work. Both instances are now eligible to receive application traffic from the load balancer.
What Does Healthy Prove?
A healthy target has responded successfully to the load balancer's checks. The load balancer can include that instance when it selects where to send a request.
Waiting for Both Targets?
Target registration can lag behind an instance entering InService. A short wait is normal while the health checks complete.
- Refresh the target list after a short wait.
- Confirm that the corresponding group instance still shows InService on the Instance management tab.
Help me diagnose a target that is not healthy.
Prove the page stays available
Healthy target status proves that both instances can receive traffic. Reloading the application proves that the expanded pool still delivers the expected page to you.
Before you check, do you expect the page to remain available while the load balancer uses the expanded target pool?
- Switch back to the browser tab showing ApplicationURL from earlier.
- Reload the page several times.
You should keep seeing Elastic Web Tier with the stack name auto-scaling-web-tier.
- Return to the target group's Targets tab.
- Refresh the target list.
You should still see two registered targets with the state healthy. Together, the working page and healthy target pool prove that the expanded web tier is ready to serve requests.
What You Have Proved
- The auto-scaling-web-tier stack remains CREATE_COMPLETE with its outputs available.
- ApplicationLoadBalancer is internet-facing with an HTTP listener on port 80 forwarding to WebTargetGroup.
- RequestCountScalingPolicy uses ALBRequestCountPerTarget with a target value of 20.
- WebAutoScalingGroup uses WebLaunchTemplate with a minimum size of 1.
- The group has a maximum size of 2 with a desired capacity of 2.
- Two t3.micro instances running Amazon Linux 2023 are InService across the selected subnets.
- WebTargetGroup has two registered targets that are healthy on HTTP port 80.
- ApplicationURL continues to serve the Elastic Web Tier page.
Secret mission
Secret Mission: Break an Instance and Watch It Heal
Your web tier now has two healthy instances. Deliberately terminate one. Prove the Auto Scaling group restores capacity while the page stays reachable.
Clean Up Your Resources
Clean Up Your Resources
Live AWS resources can keep generating usage-based charges after the lab ends. Choose whether to keep your environment running, pause its compute capacity, or delete it entirely.
Cost warning
- The Application Load Balancer can continue generating hourly charges.
- Each running Amazon EC2 instance can continue generating compute charges.
- Attached Amazon EBS volumes can continue generating storage charges.
- Public IPv4 addresses can continue generating address charges.
- Load balancer capacity unit usage can add charges.
- Data transfer can add charges.
Pausing stops the EC2 compute capacity after the instances terminate. The load balancer can still generate charges.
Deleting the stack removes its live resources. Choose this option when you have finished the lab.
Resources you used:
- An AWS CloudFormation stack named auto-scaling-web-tier.
- The load balancer represented by ApplicationLoadBalancer.
- The HTTP listener represented by WebListener.
- The target group represented by WebTargetGroup.
- The launch template represented by WebLaunchTemplate.
- The Amazon EC2 Auto Scaling group represented by WebAutoScalingGroup.
- Two t3.micro instances currently managed by the Auto Scaling group.
- The load balancer security group represented by LoadBalancerSecurityGroup.
- The instance security group represented by InstanceSecurityGroup.
- The target-tracking policy represented by RequestCountScalingPolicy.
- The Amazon CloudWatch alarms managed by target tracking.
- Any dedicated Amazon S3 bucket created by Template Studio to store the template.
Keep everything running
Leave the environment deployed if you want to continue testing its scaling behavior. No cleanup action is required.
- The auto-scaling-web-tier stack stays deployed.
- The load balancer keeps serving ApplicationURL.
- The Auto Scaling group can adjust capacity between 1 and 2 instances.
- Usage-based charges continue while the resources exist.
Pause - I'll come back to this later
Reduce the Auto Scaling group to zero instances when you want to preserve the stack without paying for active compute. The load balancer can still generate charges while the stack remains deployed.
- Return to Auto Scaling Groups in Amazon EC2.
- Select the group identified by the AutoScalingGroupName output from earlier.
- Edit the group's capacity settings.
- Set its minimum capacity to 0.
- Set its desired capacity to 0.
- Save the capacity changes.
- Open the Instance management tab.
- Wait until no instance remains in the InService lifecycle state.
Good call. Your EC2 compute capacity is now paused while the load balancer remains deployed.
- Edit the group's capacity settings again when you are ready to resume.
- Set its desired capacity to 1.
- Set its minimum capacity to 1.
- Save the capacity changes.
- Open the Instance management tab.
- Wait until one instance reaches the InService lifecycle state.
Delete - I don't want to use this again
Deleting the stack is permanent for this deployed environment. It removes the project resources without deleting your AWS account.
- Return to AWS CloudFormation.
- Select the auto-scaling-web-tier stack.
- Choose Delete.
- Confirm the deletion.
- Watch the stack status change to DELETE_IN_PROGRESS.
- Refresh the stack list until auto-scaling-web-tier no longer appears.
That is the main cleanup complete. The load balancer and its Auto Scaling resources have now been removed.
A dedicated Template Studio bucket sits outside the deleted stack. Clean it up separately only if Template Studio created one for this project.
- Skip the remaining actions if Template Studio did not create a dedicated bucket.
- Open the dedicated Template Studio bucket in Amazon S3.
- Delete every template object in that bucket.
- Return to the Amazon S3 bucket list.
- Delete the empty bucket.
- Confirm the dedicated bucket no longer appears in the bucket list.
Your AWS environment is now cleared of the project resources that could continue generating charges.
Nice Work!
Nice Work!
Excellent work! Your Amazon EC2 web tier now adds capacity under traffic through an Application Load Balancer.
You've learned how to:
- Serve the Elastic Web Tier page through an internet-facing Application Load Balancer backed by healthy Amazon EC2 targets.
- Deploy an Amazon EC2 Auto Scaling group across two Availability Zones from a reusable CloudFormation template.
- Prove traffic-driven scale-out by pushing ALBRequestCountPerTarget above its target until a second instance reached InService.
- Secret Mission: Prove self-healing after terminating one live instance by watching Amazon EC2 Auto Scaling restore two healthy targets.
Ready to quiz yourself?