Engineering case study
Terraform · AWS · Three-tier architecture
Book Review: a modular three-tier AWS foundation
A Terraform scaffold that separates a Next.js frontend, Node.js API, and MySQL database across public and private network tiers, with controlled traffic paths between each layer.
5
Terraform modules
6
purpose-built subnets
3
isolated application tiers
2
application load balancers
The problem
What needed to be solved
The application needed more than a single public server. Web traffic, application traffic, and database access had to follow explicit paths while the infrastructure remained understandable enough to reproduce and extend.
My role
What I owned
I designed the Terraform module boundaries, network topology, security-group relationships, load-balancer routing, EC2 bootstrap automation, and the RDS integration. The focus was infrastructure and deployment automation for an existing application codebase.
Architecture
How the system fits together
Internet
HTTP entry point
Public ALB
Spans two web subnets
Web EC2
Nginx + Next.js frontend
Internal ALB
Private API routing on :3001
App EC2
Node.js API in a private subnet
RDS MySQL
Database subnets; app-tier access only
Key decisions
Engineering choices and trade-offs
Module boundaries follow infrastructure concerns
Networking, security, compute, load balancing, and database resources live in five focused modules. Outputs form explicit contracts between them.
Security groups describe the traffic graph
The web tier accepts traffic from the public ALB, the API accepts traffic from the internal ALB, and MySQL accepts traffic only from the API security group.
Private tiers retain controlled outbound access
A NAT gateway supports package installation and application bootstrapping without assigning public addresses to the API or database tiers.
Instances bootstrap from infrastructure outputs
Terraform templates inject ALB and RDS endpoints into user-data scripts, reducing manual configuration after provisioning.
Terraform snapshot
Infrastructure outputs are wired into compute bootstrapping
The root module composes the five infrastructure concerns and passes generated load-balancer and database endpoints into each EC2 tier.
Inspect the source filemodule "ec2" {
source = "./modules/ec2"
web_user_data = templatefile("scripts/frontend-userdata.sh.tpl", {
public_alb_dns = module.alb.public_alb_dns_name
private_alb_dns = module.alb.private_alb_dns_name
})
app_user_data = templatefile("scripts/backend-userdata.sh.tpl", {
db_host = split(":", module.database.db_endpoint)[0]
db_name = var.db_name
})
} Measurable outcome
What the implementation demonstrates
- One Terraform root expresses five reusable modules, six subnets across two availability zones, two application load balancers, two compute tiers, and one managed database.
- The API and database have no direct internet ingress; access is chained through security-group references instead of broad CIDR rules.
- Frontend and backend installation, configuration, process supervision, and Nginx routing are automated through EC2 user data.
- The reusable module boundaries make the scaffold easier to extend without collapsing networking, security, compute, load balancing, and data resources into one file.