Build a Production-Ready AWS VPC with Terraform
Learn how to provision a reusable AWS VPC using Terraform, including public and private subnets, an Internet Gateway, route tables, and security groups. This beginner-friendly guide explains the essential components, deployment commands, and cleanup steps.
Build a Production-Ready AWS VPC with Terraform
Infrastructure as Code (IaC) lets you create, update, and manage cloud infrastructure through version-controlled configuration files. Terraform is one of the most widely used IaC tools because it supports AWS and many other providers.
In this article, you will create a basic AWS VPC environment using Terraform. The architecture includes:
- A VPC
- One public subnet
- One private subnet
- An Internet Gateway
- Route tables and route table associations
- A security group for web traffic
Note: Always runterraform destroyafter testing if you do not need the infrastructure anymore. This helps avoid unnecessary AWS charges.
Prerequisites
Before starting, make sure you have:
- An AWS account
- AWS CLI installed and configured
- Terraform installed
- Basic knowledge of AWS networking
- An IAM user or role with permissions to create VPC resources
Verify your installations:
1
2
aws --version
terraform --versionProject structure
Create a new folder for the project:
1
2
mkdir terraform-aws-vpc
cd terraform-aws-vpcCreate these files:
1
2
3
4
terraform-aws-vpc/
├── main.tf
├── variables.tf
└── outputs.tfConfigure the AWS provider
Add the following to
main.tf:1
2
3
4
5
6
7
8
9
10
11
12
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = var.aws_region
}Define variables
Create
variables.tf:1
2
3
4
5
6
7
8
9
10
11
variable "aws_region" {
description = "AWS Region for resources"
type = string
default = "ap-south-1"
}
variable "vpc_cidr" {
description = "CIDR block for the VPC"
type = string
default = "10.0.0.0/16"
}Create the VPC
Add this to
main.tf:1
2
3
4
5
6
7
8
9
10
11
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "terraform-demo-vpc"
Environment = "dev"
ManagedBy = "Terraform"
}
}This creates an isolated network with the CIDR range
10.0.0.0/16.Create public and private subnets
Add the following resources:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
availability_zone = "ap-south-1a"
map_public_ip_on_launch = true
tags = {
Name = "public-subnet"
}
}
resource "aws_subnet" "private" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.2.0/24"
availability_zone = "ap-south-1b"
tags = {
Name = "private-subnet"
}
}A public subnet can host resources that need direct internet access, such as an Application Load Balancer or a bastion host. A private subnet is suitable for application servers, databases, and internal services.
Add an Internet Gateway
An Internet Gateway enables communication between your VPC and the internet.
1
2
3
4
5
6
7
resource "aws_internet_gateway" "igw" {
vpc_id = aws_vpc.main.id
tags = {
Name = "terraform-demo-igw"
}
}Configure a public route table
Create a route table that sends internet-bound traffic through the Internet Gateway:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.igw.id
}
tags = {
Name = "public-route-table"
}
}
resource "aws_route_table_association" "public" {
subnet_id = aws_subnet.public.id
route_table_id = aws_route_table.public.id
}Create a security group
This example security group allows HTTP traffic from the internet. In production, restrict access based on your actual requirements.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
resource "aws_security_group" "web" {
name = "web-security-group"
description = "Allow HTTP inbound traffic"
vpc_id = aws_vpc.main.id
ingress {
description = "HTTP from the internet"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
description = "Allow all outbound traffic"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "web-security-group"
}
}Add outputs
Create
outputs.tf:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
output "vpc_id" {
value = aws_vpc.main.id
}
output "public_subnet_id" {
value = aws_subnet.public.id
}
output "private_subnet_id" {
value = aws_subnet.private.id
}
output "web_security_group_id" {
value = aws_security_group.web.id
}Deploy the infrastructure
Initialize Terraform:
1
terraform initReview the resources Terraform plans to create:
1
terraform planApply the configuration:
1
terraform applyType
yes when Terraform asks for confirmation.After deployment, Terraform will display the VPC, subnet, and security group IDs.
Verify resources in AWS
Open the AWS Management Console and check:
- VPC dashboard for the new VPC
- Subnets section for public and private subnets
- Internet Gateways for the attached gateway
- Route Tables for the public route
- Security Groups for the HTTP rule
Clean up resources
When you finish testing, remove all resources created by Terraform:
1
terraform destroyReview the deletion plan and type
yes to confirm.Conclusion
You have created a foundational AWS network using Terraform. This VPC design can be extended by adding:
- NAT Gateway for private subnet internet access
- EC2 instances or ECS services
- Application Load Balancer
- Amazon RDS in private subnets
- AWS WAF for application protection
- CloudWatch logging and monitoring
- CI/CD workflows using GitHub Actions or GitLab CI
Using Terraform makes infrastructure repeatable, reviewable, and easier to manage as your AWS environment grows.
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article