DEV Community

Mary Mutua
Mary Mutua

Posted on

Deploying a Highly Available Web App on AWS Using Terraform

Today’s Terraform work took me from a single configurable EC2 web server to a clustered, load-balanced deployment on AWS.

The two big ideas I focused on were:

  • using input variables to remove hardcoded values
  • moving from a single server setup to a highly available architecture using an Application Load Balancer (ALB) and an Auto Scaling Group (ASG)

From Hardcoded to Configurable

A hardcoded Terraform setup works once, but it becomes difficult to reuse. If region, instance type, and port are written directly in main.tf, every change means editing the infrastructure code itself.

That’s where input variables help.

With Terraform variables, I could define settings like:

  • AWS region
  • EC2 instance type
  • application port
  • environment name
  • server name

and then reference them in Terraform with:

var.<name> 

Enter fullscreen mode Exit fullscreen mode

For example:

variable "server_port" {
  description = "The port the server will use for HTTP requests"
  type        = number
  default     = 8080
}

variable "instance_type" {
  description = "EC2 instance type"
  type        = string
  default     = "t3.micro"
}

Enter fullscreen mode Exit fullscreen mode

This made the infrastructure reusable without changing the main logic.

Building the Configurable Web Server

For the first lab, I deployed a single EC2 web server using:

  • an AWS provider configured with a variable-driven region
  • a security group that allowed traffic on the configured application port
  • an EC2 instance using user_data to install and run a simple web page

I also used Terraform data sources to look up:

  • the default VPC
  • default subnets
  • a current Ubuntu AMI

The important thing here was that the infrastructure behavior came from variables instead of hardcoded values.

After terraform apply, I was able to open the EC2 public DNS in the browser and confirm the page was working.

From Single Server to Clustered Architecture

The next step was to make the app more resilient.

A single EC2 instance is simple, but if that instance fails, the application goes down with it. To improve that, I built a clustered version using:

  • Application Load Balancer (ALB)
  • Target Group
  • Listener
  • Launch Template
  • Auto Scaling Group (ASG)

The request flow looked like this:

Browser -> ALB -> Target Group -> EC2 instances in Auto Scaling Group

In this design:

  • the ALB receives traffic from users
  • the listener forwards traffic to the target group
  • the target group tracks healthy EC2 instances
  • the launch template defines how instances should be created
  • the ASG keeps the desired number of instances running

I also used this Terraform data source to fetch availability zones dynamically:
data "aws_availability_zones" "all" {}

That was important because the clustered setup needed to work across multiple subnets and availability zones.

Why This Matters

The difference between the two deployments became much clearer as I worked through them.

Configurable web server

  • one EC2 instance
  • simpler to understand
  • direct browser-to-instance access
  • variables make the setup reusable

Clustered web server

  • multiple EC2 instances
  • traffic goes through the ALB
  • instances are managed by the ASG
  • better availability and closer to real production architecture

Documentation Matters Too

Part of today’s work was also exploring the Terraform documentation for:

  • aws_autoscaling_group
  • aws_lb
  • input variables

This reminded me that learning Terraform is not just about writing code. It is also about understanding the official docs, knowing what resource arguments mean, and being able to connect Terraform blocks to real architecture decisions.

Challenges I Ran Into

Today was not easy. I had to think through:

  • the difference between variable, resource, and data
  • how load balancing changes application access
  • AWS Free Tier considerations
  • how scaling architecture differs from a single-server deployment

But seeing both deployments work in the browser made everything much more concrete.

Final Thoughts

The biggest lesson for me today was this:

  • input variables make Terraform flexible
  • ALBs and ASGs make infrastructure more resilient

By the end of the day, I had successfully deployed:

  • a configurable single EC2 web server
  • a clustered web app behind an Application Load Balancer

That was a big step in understanding how Terraform moves from simple infrastructure to something much closer to real-world cloud architecture.

Follow My Journey

This is Day 4 of my 30-Day Terraform Challenge.

See you on Day 5 🚀

Top comments (0)