As part of my hands-on learning in AWS an
Terraform, I built a production-style web architecture that follows real-world cloud and DevOps best practices.
Instead of exposing EC2 instances directly to the internet, this project uses an Application Load Balancer (ALB) in public subnets and Auto Scaling Group (ASG)βmanaged EC2 instances running in private subnets, with outbound internet access provided via a NAT Gateway.
The entire infrastructure is provisioned using Terraform (Infrastructure as Code).
π GitHub Repository:
https://github.com/manoop98/terraform-aws-alb-asg-nginx
Architecture Overview
High-level flow
Internet
|
Application Load Balancer (Public)
|
Target Group (Port 8000)
|
Auto Scaling Group
|
EC2 Instances (Private Subnets)
|
Docker + Nginx
|
NAT Gateway (Outbound Internet)
Key design principles
β Only the ALB is public
β EC2 instances live in private subnets
β Auto Scaling Group ensures availability
β NAT Gateway enables outbound access securely
β Fully automated using Terraform
This architecture closely mirrors what is commonly used in production AWS environments.
Tech Stack
AWS
VPC
EC2
Application Load Balancer
Auto Scaling Group
Internet Gateway
NAT Gateway
Terraform β Infrastructure as Code
Docker β Application runtime
Nginx β Demo web server
Project Structure
terraform-aws-alb-asg-nginx/
βββ alb.tf
βββ asg.tf
βββ network.tf
βββ provider.tf
βββ security_groups.tf
βββ vpc.tf
βββ userdata.sh
βββ outputs.tf
βββ .gitignore
βββ README.md
How It Works
1οΈβ£ Networking Layer
A custom VPC is created with:
Two public subnets
Two private subnets
An Internet Gateway is attached to the VPC
Public subnets route traffic to the Internet Gateway
Private subnets route outbound traffic through a NAT Gateway
2οΈβ£ Application Load Balancer
The ALB is deployed in public subnets
Listens on HTTP (port 80)
Forwards traffic to a Target Group on port 8000
3οΈβ£ Auto Scaling Group
EC2 instances are launched using a Launch Template
Instances are placed only in private subnets
ASG automatically registers instances with the target group
Health checks are handled by the ALB
4οΈβ£ EC2 User Data & Application
Each EC2 instance runs a simple Dockerized Nginx server using user data:
!/bin/bash
yum update -y
yum install docker -y
systemctl start docker
systemctl enable docker
docker run -d -p 8000:80 nginx
This ensures:
Instances are ready immediately after launch
Target group health checks pass
ALB traffic works without manual intervention
Key Challenges & Learnings
This project was not just about writing Terraform β it involved real troubleshooting, which was the most valuable part.
Some key learnings:
AMI IDs are region-specific
β Solved by using a dynamic AMI data source
ALB requires an Internet Gateway
β Public subnets must have a route to IGW
Private EC2 instances need NAT Gateway
β Without NAT, Docker pulls and updates fail
Not all Docker images serve content by default
β Switched to Nginx for predictable behavior
Target group health checks are critical
β Correct ports and paths are essential
These are the same challenges faced in real-world production environments.
Final Result
After terraform apply, the output provides an ALB DNS name.
Opening it in a browser displays the Nginx welcome page, served from EC2 instances running in private subnets.
β Secure
β Scalable
β Highly available
β Fully automated
Why This Project Matters
This project helped me gain hands-on experience with:
AWS networking fundamentals
Secure cloud architecture design
Auto Scaling and Load Balancing
Terraform best practices
Debugging real infrastructure issues
It reflects how modern DevOps teams build and manage cloud infrastructure.
Source Code
π GitHub Repository:
https://github.com/manoop98/terraform-aws-alb-asg-nginx
Conclusion
Building this project significantly improved my understanding of AWS infrastructure and Terraform.
It reinforced the importance of security-first design, automation, and incremental validation.
If youβre learning AWS or Terraform, I highly recommend building something similar β the lessons learned are invaluable.
Thanks for reading! π
Top comments (0)