Sample: Terraform Configuration (AWS ECS Fargate)
The Infrastructure Launch Kit gives technical founders everything they need to go
from zero to a production-grade AWS deployment in a single afternoon. Instead of stitching together
blog posts and out-of-date tutorials, you get 8 battle-tested deliverables covering
networking, containers, load balancing, CI/CD, monitoring, and secrets management — all wired
together and ready to terraform apply.
Below is one sample from the kit: the core main.tf Terraform configuration that provisions a VPC, ECS Fargate cluster, Application Load Balancer, and all supporting resources. The full kit includes parameterized modules, environment configs, and a step-by-step deployment guide.
This Terraform configuration provisions the core infrastructure stack on AWS. It creates an isolated VPC with public and private subnets, an ECS Fargate cluster for running containers, an Application Load Balancer for traffic distribution, and the security groups to lock it all down.
1# ============================================================ 2# Infrastructure Launch Kit — main.tf 3# Production-grade AWS ECS Fargate with ALB 4# Founder Stack © 2026 5# ============================================================ 6 7terraform { 8 required_version = ">= 1.5.0" 9 10 required_providers { 11 aws = { 12 source = "hashicorp/aws" 13 version = "~> 5.30" 14 } 15 } 16 17 backend "s3" { 18 bucket = "myapp-terraform-state" 19 key = "prod/infrastructure.tfstate" 20 region = "us-east-1" 21 encrypt = true 22 dynamodb_table = "terraform-lock" 23 } 24} 25 26provider "aws" { 27 region = var.aws_region 28 29 default_tags { 30 tags = { 31 Project = var.project_name 32 Environment = var.environment 33 ManagedBy = "terraform" 34 } 35 } 36} 37 38# ----------------------------------------------- 39# Variables 40# ----------------------------------------------- 41 42variable "aws_region" { 43 description = "AWS region for all resources" 44 type = string 45 default = "us-east-1" 46} 47 48variable "project_name" { 49 description = "Name prefix for all resources" 50 type = string 51 default = "myapp" 52} 53 54variable "environment" { 55 description = "Deployment environment (prod, staging, dev)" 56 type = string 57 default = "prod" 58} 59 60variable "container_port" { 61 description = "Port the container listens on" 62 type = number 63 default = 3000 64} 65 66variable "container_image" { 67 description = "Docker image URI (ECR or Docker Hub)" 68 type = string 69} 70 71# ----------------------------------------------- 72# Data Sources 73# ----------------------------------------------- 74 75data "aws_availability_zones" "available" { 76 state = "available" 77} 78 79# ----------------------------------------------- 80# VPC & Networking 81# ----------------------------------------------- 82 83resource "aws_vpc" "main" { 84 cidr_block = "10.0.0.0/16" 85 enable_dns_hostnames = true 86 enable_dns_support = true 87 88 tags = { 89 Name = "${var.project_name}-${var.environment}-vpc" 90 } 91} 92 93resource "aws_subnet" "public" { 94 count = 2 95 vpc_id = aws_vpc.main.id 96 cidr_block = cidrsubnet(aws_vpc.main.cidr_block, 8, count.index) 97 availability_zone = data.aws_availability_zones.available.names[count.index] 98 map_public_ip_on_launch = true 99 100 tags = { 101 Name = "${var.project_name}-public-${count.index + 1}" 102 } 103} 104 105resource "aws_subnet" "private" { 106 count = 2 107 vpc_id = aws_vpc.main.id 108 cidr_block = cidrsubnet(aws_vpc.main.cidr_block, 8, count.index + 10) 109 availability_zone = data.aws_availability_zones.available.names[count.index] 110 111 tags = { 112 Name = "${var.project_name}-private-${count.index + 1}" 113 } 114} 115 116resource "aws_internet_gateway" "main" { 117 vpc_id = aws_vpc.main.id 118 119 tags = { 120 Name = "${var.project_name}-igw" 121 } 122} 123 124resource "aws_route_table" "public" { 125 vpc_id = aws_vpc.main.id 126 127 route { 128 cidr_block = "0.0.0.0/0" 129 gateway_id = aws_internet_gateway.main.id 130 } 131 132 tags = { 133 Name = "${var.project_name}-public-rt" 134 } 135} 136 137resource "aws_route_table_association" "public" { 138 count = 2 139 subnet_id = aws_subnet.public[count.index].id 140 route_table_id = aws_route_table.public.id 141} 142 143# ----------------------------------------------- 144# Security Groups 145# ----------------------------------------------- 146 147resource "aws_security_group" "alb" { 148 name = "${var.project_name}-alb-sg" 149 description = "Allow inbound HTTP/HTTPS to ALB" 150 vpc_id = aws_vpc.main.id 151 152 ingress { 153 description = "HTTP" 154 from_port = 80 155 to_port = 80 156 protocol = "tcp" 157 cidr_blocks = ["0.0.0.0/0"] 158 } 159 160 ingress { 161 description = "HTTPS" 162 from_port = 443 163 to_port = 443 164 protocol = "tcp" 165 cidr_blocks = ["0.0.0.0/0"] 166 } 167 168 egress { 169 from_port = 0 170 to_port = 0 171 protocol = "-1" 172 cidr_blocks = ["0.0.0.0/0"] 173 } 174 175 tags = { 176 Name = "${var.project_name}-alb-sg" 177 } 178} 179 180resource "aws_security_group" "ecs_tasks" { 181 name = "${var.project_name}-ecs-tasks-sg" 182 description = "Allow inbound from ALB only" 183 vpc_id = aws_vpc.main.id 184 185 ingress { 186 description = "Allow traffic from ALB" 187 from_port = var.container_port 188 to_port = var.container_port 189 protocol = "tcp" 190 security_groups = [aws_security_group.alb.id] 191 } 192 193 egress { 194 from_port = 0 195 to_port = 0 196 protocol = "-1" 197 cidr_blocks = ["0.0.0.0/0"] 198 } 199 200 tags = { 201 Name = "${var.project_name}-ecs-tasks-sg" 202 } 203} 204 205# ----------------------------------------------- 206# Application Load Balancer 207# ----------------------------------------------- 208 209resource "aws_lb" "main" { 210 name = "${var.project_name}-alb" 211 internal = false 212 load_balancer_type = "application" 213 security_groups = [aws_security_group.alb.id] 214 subnets = aws_subnet.public[*].id 215 216 enable_deletion_protection = false 217 218 tags = { 219 Name = "${var.project_name}-alb" 220 } 221} 222 223resource "aws_lb_target_group" "app" { 224 name = "${var.project_name}-tg" 225 port = var.container_port 226 protocol = "HTTP" 227 vpc_id = aws_vpc.main.id 228 target_type = "ip" 229 230 health_check { 231 enabled = true 232 healthy_threshold = 3 233 unhealthy_threshold = 3 234 timeout = 10 235 interval = 30 236 path = "/health" 237 protocol = "HTTP" 238 matcher = "200" 239 } 240} 241 242resource "aws_lb_listener" "http" { 243 load_balancer_arn = aws_lb.main.arn 244 port = 80 245 protocol = "HTTP" 246 247 default_action { 248 type = "forward" 249 target_group_arn = aws_lb_target_group.app.arn 250 } 251} 252 253# ----------------------------------------------- 254# ECS Cluster & Fargate Service 255# ----------------------------------------------- 256 257resource "aws_ecs_cluster" "main" { 258 name = "${var.project_name}-${var.environment}" 259 260 setting { 261 name = "containerInsights" 262 value = "enabled" 263 } 264} 265 266resource "aws_ecs_task_definition" "app" { 267 family = "${var.project_name}-app" 268 network_mode = "awsvpc" 269 requires_compatibilities = ["FARGATE"] 270 cpu = "512" 271 memory = "1024" 272 execution_role_arn = aws_iam_role.ecs_execution.arn 273 task_role_arn = aws_iam_role.ecs_task.arn 274 275 container_definitions = jsonencode([{ 276 name = "app" 277 image = var.container_image 278 essential = true 279 280 portMappings = [{ 281 containerPort = var.container_port 282 protocol = "tcp" 283 }] 284 285 logConfiguration = { 286 logDriver = "awslogs" 287 options = { 288 "awslogs-group" = aws_cloudwatch_log_group.app.name 289 "awslogs-region" = var.aws_region 290 "awslogs-stream-prefix" = "ecs" 291 } 292 } 293 294 environment = [ 295 { name = "NODE_ENV", value = var.environment }, 296 { name = "PORT", value = tostring(var.container_port) }, 297 ] 298 }]) 299} 300 301resource "aws_cloudwatch_log_group" "app" { 302 name = "/ecs/${var.project_name}" 303 retention_in_days = 30 304} 305 306resource "aws_ecs_service" "app" { 307 name = "${var.project_name}-service" 308 cluster = aws_ecs_cluster.main.id 309 task_definition = aws_ecs_task_definition.app.arn 310 desired_count = 2 311 launch_type = "FARGATE" 312 313 network_configuration { 314 subnets = aws_subnet.private[*].id 315 security_groups = [aws_security_group.ecs_tasks.id] 316 assign_public_ip = false 317 } 318 319 load_balancer { 320 target_group_arn = aws_lb_target_group.app.arn 321 container_name = "app" 322 container_port = var.container_port 323 } 324 325 depends_on = [aws_lb_listener.http] 326} 327 328# ----------------------------------------------- 329# IAM Roles for ECS 330# ----------------------------------------------- 331 332resource "aws_iam_role" "ecs_execution" { 333 name = "${var.project_name}-ecs-execution-role" 334 335 assume_role_policy = jsonencode({ 336 Version = "2012-10-17" 337 Statement = [{ 338 Action = "sts:AssumeRole" 339 Effect = "Allow" 340 Principal = { Service = "ecs-tasks.amazonaws.com" } 341 }] 342 }) 343} 344 345resource "aws_iam_role_policy_attachment" "ecs_execution" { 346 role = aws_iam_role.ecs_execution.name 347 policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" 348} 349 350resource "aws_iam_role" "ecs_task" { 351 name = "${var.project_name}-ecs-task-role" 352 353 assume_role_policy = jsonencode({ 354 Version = "2012-10-17" 355 Statement = [{ 356 Action = "sts:AssumeRole" 357 Effect = "Allow" 358 Principal = { Service = "ecs-tasks.amazonaws.com" } 359 }] 360 }) 361} 362 363# ----------------------------------------------- 364# Outputs 365# ----------------------------------------------- 366 367output "alb_dns_name" { 368 description = "DNS name of the Application Load Balancer" 369 value = aws_lb.main.dns_name 370} 371 372output "ecs_cluster_name" { 373 description = "Name of the ECS cluster" 374 value = aws_ecs_cluster.main.name 375} 376 377output "ecs_service_name" { 378 description = "Name of the ECS service" 379 value = aws_ecs_service.app.name 380} 381 382output "vpc_id" { 383 description = "ID of the VPC" 384 value = aws_vpc.main.id 385}
Get all 8 production-ready deliverables. Stop guessing at AWS configs
and deploy with confidence on day one.
Battle-tested configs used in real SaaS deployments, not toy examples.
Step-by-step guide takes you from zero to production in one afternoon.
Proper VPC isolation, least-privilege IAM, and encrypted state management.