CyberPanel

AWS VPC Terraform: How to Create a VPC With Terraform

aws vpc terraform
On this page

AWS VPC Terraform configurations let you create and manage a Virtual Private Cloud through infrastructure as code instead of configuring the network manually in the AWS console. You can use the native aws_vpc resource for a simple VPC or a reusable VPC module when your network needs multiple subnets, gateways, and related resources.

This guide shows how to create an AWS VPC with Terraform, configure subnets and DNS settings, use the terraform-aws-modules/vpc/aws module, and troubleshoot common configuration problems.

What Is AWS VPC Terraform?

AWS VPC Terraform means using Terraform to define Amazon VPC networking resources in configuration files. Terraform uses the AWS provider to communicate with AWS and create the resources described in your configuration. The AWS provider includes the aws_vpc resource for creating a VPC.

A basic VPC can be created with:

resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"

  tags = {
    Name = "main-vpc"
  }
}

The cidr_block defines the IPv4 address range for the VPC. The AWS provider also supports settings such as DNS support, DNS hostnames, IPv6 allocation, tenancy, and tags.

For a small test environment, this direct resource approach is easy to understand. For a production network with public and private subnets, NAT gateways, route tables, and other components, a VPC module can reduce repeated configuration.

How Do You Create an AWS VPC With Terraform?

You can create a basic AWS VPC in six steps:

  1. Configure the AWS provider.
  2. Define the VPC CIDR block.
  3. Add VPC settings and tags.
  4. Initialize Terraform.
  5. Review the execution plan.
  6. Apply the configuration.

The AWS provider can obtain its region and credentials through supported provider configuration and AWS credential mechanisms. Avoid putting long-lived access keys directly into Terraform files.

Step 1: Configure the AWS Provider

Create a main.tf file:

terraform {
  required_providers {
    aws = {
      source = "hashicorp/aws"
    }
  }
}

provider "aws" {
  region = "us-east-1"
}

The required_providers block tells Terraform which AWS provider to install. The provider block sets the AWS region used by resources that inherit this configuration.

Step 2: Define the VPC

Add the VPC resource:

resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"

  tags = {
    Name        = "terraform-vpc"
    Environment = "dev"
  }
}

Here, aws_vpc is the resource type and main is its local Terraform name.

The 10.0.0.0/16 CIDR provides the address space for this example VPC. Choose your network range based on the rest of your environment to avoid overlapping CIDRs.

Step 3: Configure DNS Settings

AWS VPCs support DNS settings that can be controlled through Terraform.

resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_support   = true
  enable_dns_hostnames = true

  tags = {
    Name = "terraform-vpc"
  }
}

The AWS provider documents enable_dns_support as enabled by default, while enable_dns_hostnames defaults to false for the aws_vpc resource.

Whether you need these settings depends on the workloads you plan to run inside the VPC.

Step 4: Initialize Terraform

Run:

terraform init

This initializes the working directory and installs the required provider and any referenced modules.

Step 5: Validate and Plan

First, check the configuration:

terraform validate

Validation requires an initialized working directory with the required plugins and modules available. For checking the configuration in the context of an actual run, HashiCorp recommends using terraform plan, which also performs validation.

Then create an execution plan:

terraform plan

Review the resources Terraform intends to create before continuing.

Step 6: Apply the Configuration

If the plan is correct, run:

terraform apply

Terraform will ask for confirmation unless you provide an appropriate automation option.

After Terraform finishes, the VPC is managed through the Terraform configuration and state rather than being a resource you need to recreate manually through the AWS console.

How Does aws_vpc Work in Terraform?

The aws_vpc resource is the main building block for an aws_vpc terraform configuration when you want to create and manage an Amazon VPC directly.

A minimal configuration is:

resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
}

You can add tags:

resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"

  tags = {
    Name = "production-vpc"
  }
}

The resource exposes attributes such as the VPC ID, ARN, main route table ID, default security group ID, and DNS settings after creation.

You can reference the VPC ID from another resource:

aws_vpc.main.id

This reference lets Terraform connect dependent resources without hardcoding the VPC ID.

For example, a subnet can reference the VPC:

resource "aws_subnet" "public" {
  vpc_id     = aws_vpc.main.id
  cidr_block = "10.0.1.0/24"

  tags = {
    Name = "public-subnet"
  }
}

Terraform automatically understands the dependency created by aws_vpc.main.id.

How to Add Public and Private Subnets

A VPC usually becomes useful when you divide its CIDR range into smaller subnet ranges.

For example:

VPC:             10.0.0.0/16

Public subnet:   10.0.1.0/24
Private subnet:  10.0.2.0/24

You can represent those subnets with Terraform:

resource "aws_subnet" "public" {
  vpc_id                  = aws_vpc.main.id
  cidr_block              = "10.0.1.0/24"
  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"

  tags = {
    Name = "private-subnet"
  }
}

Creating a subnet does not by itself make it publicly reachable. Public and private network behavior also depends on route tables, gateways, and other networking resources.

For larger configurations, define these components carefully instead of assuming that a subnet is public simply because it has a public CIDR range.

AWS VPC Terraform traffic flow between public and private subnets

Should You Use a Terraform AWS VPC Module?

You can build a VPC entirely from individual AWS resources, but a reusable module can reduce the amount of networking configuration you need to maintain.

The Terraform Registry provides the widely used terraform-aws-modules/vpc/aws module. HashiCorp’s own AWS module tutorial uses this module to create a VPC with availability zones, public subnets, private subnets, and NAT gateway settings.

The current Terraform Registry listing for the module shows version 6.7.2 as the latest release at the time of writing.

A module configuration can look like this:

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "6.7.2"

  name = "example-vpc"
  cidr = "10.0.0.0/16"

  azs = [
    "us-west-2a",
    "us-west-2b",
    "us-west-2c"
  ]

  private_subnets = [
    "10.0.1.0/24",
    "10.0.2.0/24",
    "10.0.3.0/24"
  ]

  public_subnets = [
    "10.0.101.0/24",
    "10.0.102.0/24",
    "10.0.103.0/24"
  ]

  enable_nat_gateway = true
}

The module handles a collection of VPC networking resources based on the arguments you provide. The exact inputs and behavior depend on the module version, so check its current documentation before copying a configuration into production.

When Should You Use a Module?

A module makes more sense when you need several related networking resources and want a consistent pattern across environments.

Use individual resources when:

  • You are learning how AWS networking works.
  • You need a small VPC.
  • You want direct control over every resource.
  • You are building a custom networking design.

Use a VPC module when:

  • You need multiple subnets and gateways.
  • Several environments use the same network pattern.
  • You want to reuse the same configuration.
  • You want to reduce repeated VPC resource definitions.

You can learn more about reusable Terraform building blocks in CyberPanel’s Terraform Modules guide.

How Does the Terraform AWS VPC Module Work?

The terraform-aws-modules/vpc/aws source identifies the VPC module in the Terraform Registry.

A module block generally follows this structure:

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "6.7.2"

  # Module inputs
}

Terraform downloads the module during initialization.

terraform init

The module then creates the resources defined by its configuration and exposes outputs that other parts of your Terraform configuration can reference.

For example, a module may expose a VPC ID that another resource can use:

module.vpc.vpc_id

The exact output names depend on the module version. Always check the module’s current output documentation rather than assuming an output exists.

Terraform modules are reusable sets of configuration. They can be sourced from the Terraform Registry, local directories, or other supported sources.

What Is the Difference Between aws_vpc and a VPC Module?

The main difference is the level of abstraction.

ApproachWhat you manageBest for
aws_vpcIndividual VPC resourceSimple VPCs and learning
Multiple AWS resourcesVPC, subnets, routes, gateways, security groups, etc.Custom network designs
VPC moduleA reusable group of networking resourcesLarger and repeated deployments

With aws_vpc, you directly define the VPC:

resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
}

With the module approach:

module "vpc" {
  source = "terraform-aws-modules/vpc/aws"

  name = "example-vpc"
  cidr = "10.0.0.0/16"
}

The second approach hides much of the resource-level configuration behind module inputs and outputs.

Neither approach is automatically better. The right choice depends on how much control and reuse your network requires.

How to Use Variables With AWS VPC Terraform

Variables make your VPC configuration easier to reuse.

For example:

variable "vpc_cidr" {
  type        = string
  description = "CIDR block for the VPC"
  default     = "10.0.0.0/16"
}

Use it in the VPC:

resource "aws_vpc" "main" {
  cidr_block = var.vpc_cidr

  tags = {
    Name = "terraform-vpc"
  }
}

You can then provide a different value through a .tfvars file:

vpc_cidr = "10.10.0.0/16"

This keeps the resource definition separate from environment-specific values.

How to Retrieve an Existing VPC With Terraform

You do not always need to create a VPC.

If an AWS VPC already exists, Terraform can retrieve information about it using the aws_vpc data source.

For example:

variable "vpc_id" {
  type = string
}

data "aws_vpc" "selected" {
  id = var.vpc_id
}

You can then reference:

data.aws_vpc.selected.id

The AWS provider documents the aws_vpc data source for retrieving details about a specific existing VPC. This is useful when another part of your configuration needs information about a VPC that Terraform is not creating.

CyberPanel’s Terraform Data Guide covers data sources and how Terraform can retrieve information from existing AWS resources.

How to Validate an AWS VPC Terraform Configuration

Run the following before applying changes:

terraform fmt
terraform validate
terraform plan

Each command has a different purpose.

CommandPurpose
terraform fmtFormats Terraform configuration
terraform validateChecks configuration syntax and internal consistency
terraform planShows the changes Terraform intends to make

terraform validate requires an initialized working directory. For a validation-only initialization that does not access the configured backend, HashiCorp documents terraform init -backend=false.

For a complete overview of the validation command, see CyberPanel’s Terraform Validate guide.

Common AWS VPC Terraform Errors

Error: Provider configuration is missing

If Terraform cannot find the AWS provider configuration, check that your configuration declares the AWS provider and that the working directory has been initialized.

Run:

terraform init

Also verify your required_providers and provider "aws" blocks.

Error: Invalid provider configuration

This can happen when Terraform cannot determine the AWS region or credentials.

Check your AWS authentication and region configuration before running:

terraform plan

Do not place permanent AWS secret keys directly in a Terraform file that could enter source control.

Error: CIDR blocks overlap

A VPC and its subnets must use address ranges that make sense within the network design.

For example:

VPC:              10.0.0.0/16
Public subnet:    10.0.1.0/24
Private subnet:   10.0.2.0/24

Plan your CIDR ranges before creating multiple VPCs or connecting networks. Overlapping networks can cause problems when you later add peering, transit networking, or other connectivity.

Error: Module version or source problems

If Terraform cannot install a VPC module, check the source and version arguments.

Then run:

terraform init

If you changed the module source or version, Terraform may need to update the module installation.

Error: Changes are not what you expected

Never skip terraform plan for an important network change.

Review the planned resources, CIDR ranges, subnets, and gateway changes before running:

terraform apply

Network changes can affect workloads that depend on the VPC.

Best Practices for AWS VPC Terraform

Follow these practices when managing VPC infrastructure with Terraform:

  1. Plan your CIDR ranges first. Leave enough address space for future subnets.
  2. Use variables for environment-specific values. This keeps reusable configurations clean.
  3. Tag VPC resources consistently. Names and environment tags make AWS resources easier to identify.
  4. Use modules when the network pattern is repeated. Avoid copying large VPC configurations between environments.
  5. Pin module versions. This makes module behavior more predictable between deployments.
  6. Review terraform plan before applying network changes.
  7. Keep AWS credentials out of .tf files.
  8. Use terraform validate and formatting checks before committing changes.
  9. Document public and private subnet intent. A subnet’s name alone does not determine its routing behavior.
  10. Do not expose more module inputs than you need. A smaller module interface is easier to maintain.

FAQs

What CIDR should I use for a Terraform AWS VPC?

There is no single CIDR that fits every environment. Choose an address range that provides enough space for your planned subnets and does not overlap with networks that need to communicate with the VPC.

Does creating a VPC automatically create public subnets?

No. A VPC and its subnets are separate resources. Public subnet behavior also depends on routing and gateway configuration.

What does terraform-aws-modules/vpc/aws do?

It is a reusable Terraform module for creating AWS VPC resources. Its configuration can include the VPC, public and private subnets, availability zones, NAT gateways, and other networking components depending on the inputs provided.

Final Takeaway

AWS VPC Terraform configurations give you a repeatable way to define and manage AWS networking. Start with aws_vpc when you need direct resource-level control. Move to a VPC module when the configuration grows or needs to be reused across environments.

The key is to plan the network before applying it. Choose the CIDR ranges, define the subnet layout, review the Terraform plan, and keep module versions under control.

Ready to build your AWS VPC? Define your CIDR and subnet plan, run terraform plan, review every network change, and apply the configuration only after the plan matches your design.

Leave a Reply

Your email address will not be published. Required fields are marked *

Chat on WhatsApp