This content originally appeared on DEV Community and was authored by Latchu@DevOps
📘 Scenario
Your company wants to standardize the AWS network setup across all environments — dev, stage, and prod.
Architects want a Terraform VPC module that:
- Creates a VPC with configurable CIDR
- Creates customizable public and private subnets
- Creates an Internet Gateway
- Creates NAT Gateways (only for stage & prod)
- Expose outputs so other teams can use the VPC module
Your task is to:
- Build a reusable Terraform VPC module
- Deploy the module for dev, stage, prod
- Make the module flexible using variables
🎯 What You Will Learn
- How to write a Terraform module
- How to structure multi-environment Terraform directories
- How to use variables & outputs
- How to control resources using count and conditional logic
- How to avoid repeated code
📁 Final Directory Structure (Goal)
terraform-task-02/
├── envs
│ ├── dev
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── terraform.tfvars
│ ├── stage
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── terraform.tfvars
│ └── prod
│ ├── main.tf
│ ├── variables.tf
│ └── terraform.tfvars
└── modules
└── vpc
├── main.tf
├── variables.tf
└── outputs.tf
🧩 Step 1: Create the VPC Module
modules/vpc/variables.tf
variable "vpc_cidr" {
type = string
}
variable "public_subnets" {
type = list(string)
}
variable "private_subnets" {
type = list(string)
}
variable "enable_nat" {
type = bool
default = false
}
variable "tags" {
type = map(string)
default = {}
}
modules/vpc/main.tf
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = merge(var.tags, {
Name = "main-vpc"
})
}
resource "aws_internet_gateway" "igw" {
vpc_id = aws_vpc.main.id
tags = {
Name = "igw"
}
}
resource "aws_subnet" "public" {
count = length(var.public_subnets)
vpc_id = aws_vpc.main.id
cidr_block = var.public_subnets[count.index]
map_public_ip_on_launch = true
tags = {
Name = "public-${count.index}"
}
}
resource "aws_subnet" "private" {
count = length(var.private_subnets)
vpc_id = aws_vpc.main.id
cidr_block = var.private_subnets[count.index]
tags = {
Name = "private-${count.index}"
}
}
# NAT only if enabled
resource "aws_eip" "nat" {
count = var.enable_nat ? 1 : 0
}
resource "aws_nat_gateway" "nat" {
count = var.enable_nat ? 1 : 0
subnet_id = aws_subnet.public[0].id
allocation_id = aws_eip.nat[0].id
}
modules/vpc/outputs.tf
output "vpc_id" {
value = aws_vpc.main.id
}
output "public_subnets" {
value = aws_subnet.public[*].id
}
output "private_subnets" {
value = aws_subnet.private[*].id
}
output "nat_gateway_id" {
value = var.enable_nat ? aws_nat_gateway.nat[0].id : null
}
🧩 Step 2: Create Environment Configurations
🔹 envs/dev/variables.tf
variable "vpc_cidr" {}
variable "public_subnets" {}
variable "private_subnets" {}
variable "enable_nat" {}
🔹 envs/dev/main.tf
provider "aws" {
region = "us-east-1"
}
module "vpc" {
source = "../../modules/vpc"
vpc_cidr = var.vpc_cidr
public_subnets = var.public_subnets
private_subnets = var.private_subnets
enable_nat = var.enable_nat
tags = {
Environment = "dev"
}
}
🔹 envs/dev/terraform.tfvars
vpc_cidr = "10.0.0.0/16"
public_subnets = [
"10.0.1.0/24",
"10.0.2.0/24"
]
private_subnets = [
"10.0.11.0/24",
"10.0.12.0/24"
]
enable_nat = false
Same as dev, except NAT enabled:
🔹 envs/stage/variables.tf
variable "vpc_cidr" {}
variable "public_subnets" {}
variable "private_subnets" {}
variable "enable_nat" {}
🔹 envs/stage/main.tf
provider "aws" {
region = "us-east-1"
}
module "vpc" {
source = "../../modules/vpc"
vpc_cidr = var.vpc_cidr
public_subnets = var.public_subnets
private_subnets = var.private_subnets
enable_nat = var.enable_nat
tags = {
Environment = "stage"
}
}
🔹 envs/stage/terraform.tfvars
vpc_cidr = "10.1.0.0/16"
public_subnets = [
"10.1.1.0/24",
"10.1.2.0/24"
]
private_subnets = [
"10.1.11.0/24",
"10.1.12.0/24"
]
enable_nat = true
🔹 envs/prod/variables.tf
variable "vpc_cidr" {}
variable "public_subnets" {}
variable "private_subnets" {}
variable "enable_nat" {}
🔹 envs/prod/main.tf
provider "aws" {
region = "us-east-1"
}
module "vpc" {
source = "../../modules/vpc"
vpc_cidr = var.vpc_cidr
public_subnets = var.public_subnets
private_subnets = var.private_subnets
enable_nat = var.enable_nat
tags = {
Environment = "prod"
}
}
🔹 envs/prod/terraform.tfvars
vpc_cidr = "10.2.0.0/16"
public_subnets = [
"10.2.1.0/24",
"10.2.2.0/24"
]
private_subnets = [
"10.2.11.0/24",
"10.2.12.0/24"
]
enable_nat = true
🚀 Step 3: Deploy the VPC
Run dev environment
cd envs/dev
terraform init
terraform plan
terraform apply
Run stage
cd envs/stage
terraform init
terraform plan
terraform apply
Run prod
cd envs/prod
terraform init
terraform plan
terraform apply
🌟 Thanks for reading! If this post added value, a like ❤️, follow, or share would encourage me to keep creating more content.
— Latchu | Senior DevOps & Cloud Engineer
☁️ AWS | GCP | ☸️ Kubernetes | 🔐 Security | ⚡ Automation
📌 Sharing hands-on guides, best practices & real-world cloud solutions
This content originally appeared on DEV Community and was authored by Latchu@DevOps
Latchu@DevOps | Sciencx (2025-11-15T10:41:52+00:00) ✅ Task 2 — Create a Reusable VPC Module with Environments using Terraform (dev/stage/prod). Retrieved from https://www.scien.cx/2025/11/15/%e2%9c%85-task-2-create-a-reusable-vpc-module-with-environments-using-terraform-dev-stage-prod/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.
