Terraform con opiniones, de nivel producción, para una aplicación web típica en AWS: VPC + subnets públicas/privadas + Auto Scaling de EC2 detrás de un ALB + RDS PostgreSQL, con estado remoto, separación de entornos y defaults conscientes del costo.
Escrito como estructuro los proyectos reales: módulos chicos y componibles, nada de entornos copiados y pegados, todo parametrizado.
┌──────────────┐
Internet ──▶│ ALB │ (subnets públicas, 2 AZs)
└──────┬───────┘
┌──────────┴──────────┐
▼ ▼
┌──────────────┐ ┌──────────────┐
│ ASG (EC2) │ │ ASG (EC2) │ (subnets privadas)
│ AZ a │ │ AZ b │
└──────┬───────┘ └──────┬───────┘
└──────────┬──────────┘
▼
┌──────────────┐
│ RDS Postgres │ (privado, Multi-AZ opcional)
└──────────────┘
modules/
├── vpc/ # VPC, subnets, NAT, route tables
├── alb/ # Application Load Balancer + target groups
├── compute/ # Launch template + Auto Scaling Group
└── rds/ # Instancia PostgreSQL + subnet group + SG
environments/
├── staging/ # t3.micro en todo, un solo NAT, sin Multi-AZ
└── production/ # instancias más grandes, RDS Multi-AZ, deletion protection
Cada entorno es una composición fina de los mismos módulos — las diferencias viven solo en los tfvars.
cd environments/staging
terraform init # configurar el backend primero (ver abajo)
terraform plan
terraform applyEl estado va en S3 con locking. Creá el bucket y la tabla una sola vez, luego descomentá el bloque backend "s3" en cada entorno:
backend "s3" {
bucket = "mi-bucket-tfstate"
key = "staging/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-locks"
encrypt = true
}- Dos AZs como mínimo — un ALB lo exige, y single-AZ no es una arquitectura real.
- Un NAT Gateway en staging, uno por AZ en producción — el NAT es la sorpresa de costo #1; staging cambia redundancia por ~USD 32/mes ahorrados.
- Sin claves SSH, sin bastion por defecto — las instancias se acceden por SSM Session Manager. Cero puertos 22 abiertos.
- RDS solo en subnets privadas, alcanzable exclusivamente desde el security group de la app (encadenamiento de SGs, no bloques CIDR).
default_tagsen el provider — cada recurso recibe tagsProjectyEnvironment; los reportes de costos funcionan desde el día uno.create_before_destroyen los launch templates — reemplazo de instancias sin downtime.
| Recurso | ~USD/mes |
|---|---|
| 1× NAT Gateway | 32 |
| 2× t3.micro (ASG) | 15 |
| ALB | 17 |
| RDS db.t3.micro | 13 |
| Total | ~77 |
(La VPC, subnets, SGs y route tables son gratis. Producción duplica esto aproximadamente con RDS Multi-AZ.)
MIT