Building a Highly Available Infrastucture using Terraform
Journey: 📊 Community Builder 📊
Subject matter: Building on AWS
Task: Building a Highly Available Infrastucture using Terraform!
This project practices Automation and Reliability.
Using the 6 Pillars of the AWS Well-Architected Framework, Operational Excellence, Security, and Reliability will be achieved in this build.
This week, I built a VPC hosting an Application Load Balancer (ALB) that balanced traffic across two EC2 Instances serving as Web servers. In the mix, there is another instance serving as a Bastion host and another instance hosting a postgres database.
Having an ALB in the environment setup ensures high availability. If we were to also add in an Auto Scaling Group, it would also increase scalability.

Resource credit: This IaC architecture was created using guidance from Christiana Shedrack on Medium Here.
What did I use to build this environment?
- Visual Studio Code platform
- Terraform
- AWS CLI
What is built?
- A single VPC
- A new EC2 Key Pair
- An S3 Bucket
- A Load Balancer (ALB)
- ALB Listeners
- ALB Target Groups
- Custom Route Tables
- Security Groups
- An Internet Gateway
- Two NAT Gateways
- Elastic IPs
- Four EC2 instances:
- Two Web servers
- One Database server
- One Bastion server
- Two websites, one hosted on each Web server, are being load-balanced
More information on Load Balancers can be found here: https://docs.aws.amazon.com/elasticloadbalancing/latest/application/introduction.html
In this task, I used Terraform to create a single VPC with an S3 Bucket storing the Terraform remote state.
I built an Application Load Balancer to distribute application traffic evenly and then hosted one EC2 instance in each Availability Zone. I used custom Route Tables and Security Groups to protect the resources in the environment and ensured the private-facing EC2 instances had an Internet Gateway so the web elements were accessible from the public internet, via the ALB.
Each EC2 Instance had a website front end built using HTML that had custom identifiers to highlight the instance being used to serve web traffic.
The ALB had a listener attached to listen for incoming connections on the specific port ID and also target groups to define how the ALB distributes traffic to the registered EC2 targets.
I used Terraform to deploy the entire environment and waited for it all to come online.
The Terraform Output identified the ALB DNS name, which I used to access the websites that had been built. Each time I refreshed the website DNS name, the ALB rerouted traffic to the other instance, demonstrating an even distribution of web traffic to serve the simple static website.

Interestingly, I ran into a problem again, which I had actually documented as a fix on my blog last year and this got me back on track again: https://www.barnybaron.com/article/20241006-ssh-connection-failing-from-windows-os/
I use VScode for my deployment, and after initially testing that I could not SSH directly to my Web servers, I SSH onto my Bastion host. From there, I copied my new Key Pair private key onto the Bastion (in a .ssh dir) and was able to jump to both Web servers and also to my Postgres database server!
From within both Web servers, I was able to get out to the internet via the NAT Gateways sitting each Availabilty Zone. I was also able to check systemctl services and generally have a look around the directory structure.
After I had completed this, I jumped onto my Postgres DB server instance from the Bastion, installed the database, checked services, and then ran some query commands.
All in all, a great lab to work from, which I would highly recommend trying out!
After documenting the lab, taking screenshots of everything, and running through various test use cases to prove the environment was secure, I then used Terraform to tear it down!
Some of the highlights…
Terraform build:

Terraform structure:

VPC built:

VPC route view:

VPC route connections:

Subnets:

Resource tagging:

Route Tables:

Routes:

Elastic IPs:

NAT Gateways:

Security Groups:

Instances:

ALB:

ALB Target Groups:

Load Balancer in action: Instance A

Load Balancer in action: Instance B

SSH to Bastion:

SSH to Postgres DB:

Database install:

Database install:

Connection to Web Server:

Web server connecting to the internet via NAT Gateway:

Web server services:

Terraform cleanup:

Environment teardown:

My interpretation of the architecture:

I hope you have enjoyed the article!

