-
Multi-Tier Web App on AWS with Terraform
AWS, Terraform, EC2, RDS (MySQL), S3, VPC, IAM, CloudWatch, SNS, Linux, Bash
-
Type
Cloud infrastructure, automation and troubleshooting project, 2026
-
Source Code
-
Work With Me
Contact me about a cloud support or operations role.
Info
A complete two-tier web application on AWS, provisioned entirely with Terraform, with monitoring, alerting and a real-world troubleshooting runbook. The application itself is intentionally minimal: the focus is the infrastructure, the automation, and the operational documentation. About 19 resources deploy and tear down with a single command, and the stack runs within free-tier and credit limits, with a billing budget and a CloudWatch billing alarm set up before anything was deployed.
Architecture
Users reach the EC2 web server in a public subnet through an internet gateway. The web server connects to a MySQL RDS database in a private subnet that only accepts traffic from the web tier's security group, and reaches S3 and CloudWatch through a least-privilege IAM role.
The Challenge
Stand up realistic infrastructure the way a cloud team would: secure by default, reproducible, monitored, and cheap to run. Then go a step further than a typical demo by deliberately breaking it — removing an IAM permission, creating state drift, and more — and diagnosing each failure from symptom to root cause, the way a support engineer works a ticket.
The Solution
Everything is defined as code in Terraform: a VPC (10.0.0.0/16) with a public subnet for the EC2 web tier and private subnets in two Availability Zones for a MySQL RDS database, an S3 bucket with public access fully blocked, a least-privilege IAM instance role, and a CloudWatch CPU alarm that emails through SNS. Twelve real failure scenarios are documented in a support-style runbook.
Key Design Choices
- Public/private subnet split: the database has no route to the internet; only the web tier can reach it.
- No NAT gateway: a deliberate cost choice, since the managed database needs no outbound internet access.
- Least-privilege IAM: the instance role grants only S3 and CloudWatch, with no long-lived keys on the server — verified by confirming that ungranted actions are denied.
- Security groups as tier-to-tier firewalls: the database trusts the web tier's security group, not an IP range; SSH is locked to a single IP.
- No secrets in code: the database password is a runtime variable, and state files, keys and variable files never reach version control.
Troubleshooting Runbook
Each scenario records the symptom, diagnostic steps, root cause and fix. Examples:
- SSH refused with "invalid format" on a valid key — PowerShell had saved it as UTF-16 instead of ASCII.
- "Access Denied" calling S3 from the instance — a missing policy on the least-privilege role.
DBInstanceAlreadyExistson apply — Terraform state drift, reconciled withterraform importinstead of rebuilding.- RDS creation failing on a password that broke the service's input rules.
- A CloudWatch alarm firing — worked through the full detect, alert, remediate and recover cycle.
What It Demonstrates
Secure multi-tier AWS design, infrastructure as code with Terraform (including state management), least-privilege IAM, monitoring and incident response with CloudWatch and SNS, cost control with budgets and routine teardown, and structured troubleshooting documented the way a support engineer documents a resolved ticket.