Create a VPC with Terraform and AWS Console

Build a VPC two ways: visually in the console, then as Terraform code.

Introduction

30 Second Summary

Imagine building a network for your application by clicking through a web interface. Now imagine needing to recreate that exact setup for a second environment, a third, or a tenth.

In this project, you will build a VPC on AWS two ways: first through the graphical console, then with Terraform code. This teaches you how Infrastructure as Code translates visual clicks into repeatable, version-controlled configuration.

What You'll Build

A VPC with a public subnet, internet gateway, and route table, built first through the AWS Console and then recreated as a Terraform configuration file.

By the end of this project, you'll have:

  • A working AWS account with CLI access configured.
  • A VPC explored through the AWS Console's visual Resource Map, showing how subnets, internet gateways, and route tables connect.
  • A Terraform configuration that creates the same infrastructure as code and can be deployed or destroyed in seconds.
  • Secret Mission: Add a private subnet in a second Availability Zone and observe how Terraform handles incremental changes.

Are there any prerequisites?

None. This project walks you through setting up every tool you need, including your AWS account, the AWS CLI, and Terraform.

Before We Start

Before you can build anything on AWS, you need the right tools installed on your machine. Terraform lets you define cloud infrastructure as code, and the AWS CLI lets you talk to AWS from your terminal.

In this step, you will install both tools and create an AWS account with the permissions needed to build VPC resources.

In this step, get ready to:
  • Install Terraform CLI.
  • Install AWS CLI v2.
  • Create an AWS account and configure programmatic access.
Install Terraform CLI

Terraform is the Infrastructure as Code tool you will use to define and deploy AWS resources from a configuration file.

  • Check if Terraform is already installed by running this command:
terraform version

✔️ I see version 1.2 or higher

Terraform is ready to go. Move on to the next substep.

ⓧ I see an older version

You need Terraform version 1.2 or higher for this project. Upgrade by re-running the install commands below, which will replace your existing version.

  • Add the HashiCorp GPG key and repository, then install by running these commands:
wget -O - https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(grep -oP '(?<=UBUNTU_CODENAME=).*' /etc/os-release || lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install terraform
  • Confirm the upgrade by running:
terraform version

You should see version 1.15.x or higher in the output.

ⓧ Command not found

Terraform is not installed yet. Follow these steps to install it from the official HashiCorp apt repository.

  • Add the HashiCorp GPG key and repository, then install Terraform by running these commands:
wget -O - https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(grep -oP '(?<=UBUNTU_CODENAME=).*' /etc/os-release || lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install terraform

What do these commands do?

  • The first command downloads and stores HashiCorp's GPG signing key so your system trusts their packages.
  • The second command adds HashiCorp's package repository to your system's sources list.
  • The third command updates your package list and installs Terraform.
  • Confirm the installation by running:
terraform version

You should see version 1.15.x or higher in the output.

Seeing a permission denied error?

  • Make sure you include sudo at the start of the install commands. You need administrator privileges to write to system directories.
  • If wget is not found, install it first with sudo apt install wget.

Still stuck? Help me troubleshoot my Terraform installation on Linux

Install AWS CLI v2

The AWS CLI is the command-line tool that lets you interact with AWS services from your terminal. You will use it to configure credentials and verify your connection to AWS.

  • Check if the AWS CLI is already installed by running:
aws --version

✔️ I see aws-cli/2.x.x

AWS CLI v2 is ready. Move on to the next substep.

ⓧ I see aws-cli/1.x.x

You have version 1 installed, but this project requires version 2. Install v2 alongside it by running the following commands.

  • Download and install AWS CLI v2 by running these commands:
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
  • Confirm the upgrade by running:
aws --version

You should now see aws-cli/2.x.x in the output.

ⓧ Command not found

AWS CLI is not installed yet. Follow these steps to install v2 using the official bundled installer.

  • Download and install AWS CLI v2 by running these commands:
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install

What do these commands do?

  • The first command downloads the official AWS CLI v2 installer as a zip file.
  • The second command extracts the installer from the zip archive.
  • The third command runs the installer with administrator privileges.
  • Confirm the installation by running:
aws --version

You should see aws-cli/2.x.x in the output.

Seeing 'unzip: command not found'?

  • Install the unzip utility first by running sudo apt install unzip, then re-run the commands above.
  • If you see a permission error on sudo ./aws/install, make sure you are using sudo to run the installer.

Still stuck? Help me troubleshoot my AWS CLI v2 installation on Linux

Create an AWS account and configure CLI access

To create resources on AWS, you need an account with programmatic access. You will create a free account, then set up an IAM user with just enough permissions to build VPC resources.

  • Open https://portal.aws.amazon.com/billing/signup in your browser and follow the prompts to create a free AWS account.
  • Once your account is created and you are signed in, open the IAM console at https://console.aws.amazon.com/iam/.
  • In the left navigation pane, choose Users.
  • Click Create user.
  • For User name, type terraform-user and click Next.
  • On the Set permissions page, select Attach policies directly.
  • In the search box, type AmazonVPCFullAccess and select the checkbox next to it.
  • Click Next, then click Create user.

What is IAM?

IAM (Identity and Access Management) controls who can access what in your AWS account. By creating a dedicated user with only VPC permissions, you follow the principle of least privilege.

The AmazonVPCFullAccess policy grants permission to create, modify, and delete VPC resources. It does not grant access to other AWS services.

Now you need to create an access key so the AWS CLI can authenticate as this user.

  • Click the user name terraform-user to open the user details page.
  • Select the Security credentials tab.
  • Under Access keys, click Create access key.
  • For the use case, select Command Line Interface (CLI) and click Next.
  • Skip the optional tag and click Create access key.
  • Click Download .csv file and save it somewhere secure. This is the only time you can view your secret access key.
  • Click Done.

Keep your access key secret

Never share your access key or commit it to version control. Treat it like a password. If you lose it, you can always delete the old key and create a new one from the IAM console.

Finally, configure the AWS CLI with your new credentials.

  • Configure the AWS CLI by running:
aws configure

What will aws configure ask?

The command prompts you for four values:

  • AWS Access Key ID - paste the access key ID from your downloaded CSV.
  • AWS Secret Access Key - paste the secret access key from your downloaded CSV.
  • Default region name - type us-east-1.
  • Default output format - type json.
  • Verify that everything is working by running:
aws sts get-caller-identity

You should see a JSON response containing your Account ID, UserId, and ARN. This confirms the CLI can authenticate with AWS.

Seeing 'Unable to locate credentials'?

  • Run aws configure again and double-check you pasted the access key ID and secret access key correctly from the CSV file.
  • Make sure you did not accidentally include extra spaces when pasting.
  • If you lost the CSV, go back to the IAM console, delete the old access key, and create a new one.

Still stuck? Help me troubleshoot my AWS CLI credentials configuration

Your tools are installed and your AWS account is ready. Next up, you will create a VPC through the AWS Console to see how the components connect visually.

Create a VPC Through the AWS Console

Your tools are installed and your AWS CLI is configured. Now it's time to build your first VPC on AWS.

Before writing any Terraform code, you will create the VPC through the AWS Console first. This gives you a visual mental model of how each networking component connects to the others, so that when you translate it into code, every line makes sense.

In this step, get ready to:
  • Create a VPC with a public subnet using the AWS Console wizard.
  • Explore the Resource Map to see how VPC components connect.
  • Delete the console-created VPC to prepare for the Terraform rebuild.
Create a VPC using the console wizard

The AWS Console has a wizard that creates a VPC and all its networking components in one go. You will use the VPC and more option, which sets up the VPC, subnet, internet gateway, and route table together.

  • Open your browser and navigate to the VPC Console at https://console.aws.amazon.com/vpc/.
  • Sign in with your AWS account credentials if prompted.
  • Click Create VPC (the orange button near the top of the page).
  • Select VPC and more at the top of the creation page.

Why VPC and more?

The "VPC and more" option creates all the networking components a VPC needs in a single step. It saves you from manually creating and linking each resource individually. You will see a live preview of the architecture as you configure it.

  • In the Name tag auto-generation field, enter console-vpc.
  • Set the IPv4 CIDR block to 10.0.0.0/16.
  • Set Number of Availability Zones to 1.
  • Set Number of public subnets to 1.
  • Set Number of private subnets to 0.
  • Set NAT gateways to None.
  • Set VPC endpoints to None.
  • Leave DNS options at their defaults (both enabled).
  • Click Create VPC at the bottom of the page.

What is a CIDR block?

A CIDR block defines the range of IP addresses available inside your VPC. The notation 10.0.0.0/16 means "all addresses from 10.0.0.0 to 10.0.255.255", giving you 65,536 possible addresses.

The public subnet you selected will use a smaller slice of that range. Think of the VPC as a building and the subnet as one floor within it.

AWS will take a few seconds to create all the resources. You should see a success banner and a list of the created resources (VPC, subnet, internet gateway, route table).

Don't see the Create VPC button?

Make sure you are in the VPC service page, not the EC2 or another service. Check that the URL in your browser contains console.aws.amazon.com/vpc.

If you see a permissions error, verify that your IAM user has the AmazonVPCFullAccess managed policy attached. Why am I getting a permissions error in the VPC Console?

Explore the Resource Map

Now that your VPC exists, you can visualize how all of its components connect. The Resource Map shows the relationships between your VPC, subnet, internet gateway, and route table in a single diagram.

  • In the navigation pane on the left, click Your VPCs.
  • Select the checkbox next to your console-vpc VPC.
  • Click the Resource map tab in the lower panel.
  • Click Show details to reveal CIDR ranges, subnet associations, and route counts.
  • Hover over each resource (VPC, subnet, route table, internet gateway) to see the connecting lines highlight.

What am I looking at in the Resource Map?

Solid lines show relationships between resources (the subnet belongs to the VPC, the route table is associated with the subnet). Dotted lines show network traffic flow (internet-bound traffic goes through the internet gateway).

Notice how the route table connects the subnet to the internet gateway. This is what makes the subnet "public". Without that route, the subnet would be isolated from the internet.

Take a moment to notice the resource IDs (they start with vpc-, subnet-, igw-, rtb-). Every AWS resource gets a unique ID that you will see referenced in Terraform output later.

Delete the console-created VPC

You have seen how the components connect visually. Now you will delete this VPC so you can rebuild the exact same thing with Terraform code in the next step.

  • In the navigation pane, click Your VPCs.
  • Select the checkbox next to your console-vpc VPC.
  • Click Actions, then select Delete VPC.
  • AWS will show a list of resources that will be deleted along with the VPC (subnets, route tables, internet gateways, security groups).
  • Type delete in the confirmation field.
  • Click Delete.

Why delete the VPC now?

You are about to recreate this exact infrastructure using Terraform. Deleting first avoids name conflicts and lets you compare the experience. With the console, you clicked through multiple screens. With Terraform, you will create all of this in one command.

Confirm the deletion worked by checking Your VPCs in the navigation pane. Your console-vpc should no longer appear in the list.

VPC still showing in the list?

Refresh the page. Deletion can take a few seconds to propagate. If the VPC shows a state other than "available", it is being deleted.

If you see an error saying resources must be deleted first, make sure you did not manually create any EC2 instances inside the VPC. The "VPC and more" wizard does not create instances, so this should not happen unless you added extra resources. Help me troubleshoot a VPC that won't delete.

Your console-created VPC is gone. Next up, you will write Terraform code that recreates this exact same infrastructure, and you will see how each console setting maps to a resource block in code.

Write the Terraform Configuration

You've seen the VPC, subnet, internet gateway, and route table working together in the console's Resource Map. Now it's time to describe that same infrastructure in code.

Terraform uses a language called HCL (HashiCorp Configuration Language) to define resources in .tf files. Each resource you clicked through in the console becomes a resource block in your configuration.

In this step, get ready to:
  • Create a project directory and a Terraform configuration file.
  • Define a VPC, public subnet, and internet gateway as code.
  • Initialize Terraform and validate your configuration.
Create your project directory and configure the provider

Before writing any resource definitions, you need a project folder and a configuration that tells Terraform which cloud provider to use.

  • Move to your Desktop by running this command:
cd ~/Desktop
  • Create your project folder and move into it by running these commands:
mkdir terraform-vpc
cd terraform-vpc
  • Confirm the folder was created by running:
pwd

You should see terraform-vpc at the end of the path.

  • Create a new file called main.tf by running:
touch main.tf
  • Open main.tf in your text editor.
  • Add the following Terraform and provider configuration:
# Tell Terraform which provider to download
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 6.0"
    }
  }

  required_version = ">= 1.2"
}

# Configure the AWS provider with your region
provider "aws" {
  region = "us-east-1"
}

What does this code do?

The terraform block defines which provider plugin to download. Here you're telling Terraform to grab the AWS provider from the HashiCorp registry, pinned to any 6.x release.

The provider block configures that plugin. Setting region = "us-east-1" tells AWS where to create your resources.

  • Save main.tf.
  • Confirm the file exists by running:
ls

You should see main.tf in the output.

Don't see main.tf?

Make sure you're inside the terraform-vpc directory. Run pwd to check your current location.

If you're in the wrong folder, run cd ~/Desktop/terraform-vpc to get back.

help me find my main.tf file

Define the VPC resource

The first networking resource to define is the VPC itself. This maps directly to the VPC you created in the console wizard.

  • In main.tf, add the following code below the provider block:
# Create the VPC with a /16 address range
resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_support   = true
  enable_dns_hostnames = true

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

What does this code do?

The resource keyword tells Terraform to create something. "aws_vpc" is the resource type (an AWS VPC), and "main" is the local name you'll use to reference it elsewhere in your code.

The CIDR block 10.0.0.0/16 gives your VPC 65,536 IP addresses. Enabling DNS support and hostnames lets instances inside the VPC resolve domain names.

  • Save main.tf.

You won't see a change yet. The next chunk adds the subnet and gateway, then you'll validate everything together.

Define the subnet and internet gateway

A VPC on its own can't reach the internet. You need a subnet to place resources in and an internet gateway to connect them to the outside world.

  • In main.tf, add the public subnet resource below the VPC resource:
# Create a public subnet inside the VPC
resource "aws_subnet" "public" {
  vpc_id                  = aws_vpc.main.id
  cidr_block              = "10.0.1.0/24"
  availability_zone       = "us-east-1a"
  map_public_ip_on_launch = true

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

What does this code do?

This creates a subnet with 256 IP addresses (/24) inside your VPC. The vpc_id = aws_vpc.main.id line is a reference. Terraform automatically knows this subnet depends on the VPC and will create them in the right order.

Setting map_public_ip_on_launch = true means any instance launched in this subnet gets a public IP automatically. That's what makes it a public subnet.

  • Add the internet gateway resource below the subnet:
# Attach an internet gateway to the VPC
resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "my-igw"
  }
}

What does this code do?

The internet gateway is the bridge between your VPC and the public internet. Without it, nothing inside the VPC could send or receive traffic from outside.

Notice how vpc_id = aws_vpc.main.id appears again. This attaches the gateway to your VPC, just like you saw in the console's Resource Map.

  • Save main.tf.

✔️ Awesome, I've got everything!

Great. Double check you've saved main.tf with all three resource blocks.

ⓧ I'd like to double check the full code

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 6.0"
    }
  }

  required_version = ">= 1.2"
}

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

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

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

resource "aws_subnet" "public" {
  vpc_id                  = aws_vpc.main.id
  cidr_block              = "10.0.1.0/24"
  availability_zone       = "us-east-1a"
  map_public_ip_on_launch = true

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

resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "my-igw"
  }
}
  • Initialize Terraform to download the AWS provider by running:
terraform init

You should see Terraform has been successfully initialized! in the output.

What does terraform init do?

This command reads your required_providers block and downloads the matching provider plugin from the HashiCorp registry. It also creates a .terraform directory to store the downloaded plugin and a .terraform.lock.hcl file to lock the exact version.

  • Confirm your configuration is syntactically valid by running:
terraform validate

You should see Success! The configuration is valid. in the output.

Seeing a validation error?

Check for missing closing braces } in your main.tf file. Every opening { needs a matching close.

Make sure vpc_id = aws_vpc.main.id is spelled exactly as shown. A typo in a resource reference causes a validation failure.

help me fix my Terraform validation error

Your Terraform configuration is valid and ready to deploy. Next up, you'll add a route table and run terraform apply to create real infrastructure on AWS.

Deploy with Terraform and Compare

In the previous step, you wrote Terraform resources for the VPC, subnet, and internet gateway. Your configuration is valid, but it cannot route traffic to the internet yet.

A public subnet needs a route table that sends outbound traffic through the internet gateway. In this step, you will add the final two resources, then deploy everything with terraform apply and compare the result to what you built by hand in Step 2.

In this step, get ready to:
  • Add a route table and route table association to your Terraform configuration.
  • Run terraform plan and terraform apply to deploy all 5 resources.
  • Compare your Terraform-created VPC to the console-created one from Step 2.
Add the route table and route table association

A route table contains rules that determine where network traffic is directed. For a subnet to be truly public, its route table must send all non-local traffic (0.0.0.0/0) to the internet gateway.

  • Open main.tf in your text editor and add the following code below the aws_internet_gateway resource:
resource "aws_route_table" "public" {
  vpc_id = aws_vpc.main.id

  # Send all non-local traffic to the internet gateway
  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.main.id
  }

  tags = {
    Name = "my-public-rt"
  }
}

# Link the public subnet to the route table above
resource "aws_route_table_association" "public" {
  subnet_id      = aws_subnet.public.id
  route_table_id = aws_route_table.public.id
}

What does this code do?

The aws_route_table resource creates a route table inside your VPC. The route block inside it says: any traffic destined for 0.0.0.0/0 (anywhere on the internet) should be sent to the internet gateway.

The aws_route_table_association resource connects your public subnet to this route table. Without this link, the subnet would use the VPC's default route table, which has no internet route.

  • Save main.tf.

Seeing a syntax error?

Make sure the new code is placed after the closing } of the aws_internet_gateway resource, not inside it. Each resource block must be its own top-level block in the file.

help me fix a syntax error in my Terraform configuration

✔️ Awesome, I've got everything!

Great. Double check you have saved main.tf before moving on.

ⓧ I'd like to double check the full code

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 6.0"
    }
  }

  required_version = ">= 1.2"
}

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

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

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

resource "aws_subnet" "public" {
  vpc_id                  = aws_vpc.main.id
  cidr_block              = "10.0.1.0/24"
  availability_zone       = "us-east-1a"
  map_public_ip_on_launch = true

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

resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "my-igw"
  }
}

resource "aws_route_table" "public" {
  vpc_id = aws_vpc.main.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.main.id
  }

  tags = {
    Name = "my-public-rt"
  }
}

resource "aws_route_table_association" "public" {
  subnet_id      = aws_subnet.public.id
  route_table_id = aws_route_table.public.id
}
Preview and deploy your infrastructure

Before Terraform creates anything on AWS, it shows you a detailed preview of what it plans to do. This is your chance to catch mistakes before they become real resources.

  • Preview what Terraform will create by running this command:
terraform plan

You should see a summary ending with a line like:

Plan: 5 to add, 0 to change, 0 to destroy.

What does this output mean?

Terraform compared your main.tf to AWS (which has nothing yet) and determined it needs to create 5 resources: the VPC, subnet, internet gateway, route table, and route table association.

Each resource in the output is marked with a + symbol, meaning it will be created. No existing resources will be changed or destroyed.

  • Deploy the infrastructure by running this command:
terraform apply
  • Terraform will show the plan again and ask for confirmation. Type yes and press Enter to confirm.

You should see output ending with:

Apply complete! Resources: 5 added, 0 changed, 0 destroyed.

What just happened?

Terraform made API calls to AWS and created all 5 resources in the correct dependency order. It created the VPC first, then the subnet and internet gateway (which depend on the VPC), then the route table, and finally the association.

Terraform figured out this order automatically by reading the references between resources (like aws_vpc.main.id).

Seeing an error about credentials?

If Terraform cannot authenticate with AWS, make sure you ran aws configure in Step 1 with valid access key credentials. Verify your credentials are working by running aws sts get-caller-identity.

help me fix a Terraform authentication error with AWS

Compare your Terraform VPC to the console VPC

Now for the payoff. You are going to look at your Terraform-created VPC in the AWS Console and confirm it matches the structure you built by hand in Step 2.

  • Switch back to the AWS Console in your browser.
  • Navigate to the VPC Console at https://console.aws.amazon.com/vpc/.
  • Click Your VPCs in the left sidebar.
  • You should see a VPC named my-terraform-vpc with CIDR 10.0.0.0/16.
  • Click on my-terraform-vpc to open its details.
  • Click the Resource map tab to see a visual diagram of all connected resources.

The Resource Map shows your VPC, subnet, internet gateway, and route table all connected. This is the same structure you saw in Step 2 when you created a VPC through the wizard.

How does the code map to the diagram?

Each resource block in your main.tf corresponds to one box in the Resource Map. The references between resources (like vpc_id = aws_vpc.main.id) are the lines connecting the boxes.

This is the core idea of Infrastructure as Code: every click you made in the console wizard in Step 2 is now a line of code you can version, review, and repeat.

Your infrastructure is live and matches what you built by hand. Next up, you will tear it all down with a single command and see how Terraform handles destruction in the correct dependency order.

Destroy and Reflect

In the last step, you deployed your Terraform configuration to AWS and confirmed it created the same infrastructure you built by hand.

Now comes the real payoff. With one command, you will tear down all five resources and watch Terraform handle the dependency order automatically. This is where Infrastructure as Code earns its keep.

In this step, get ready to:
  • Destroy all five AWS resources with a single command.
  • Observe how Terraform resolves dependency order automatically.
  • Compare the console cleanup experience to the Terraform approach.
Destroy all resources with one command

In Step 2, deleting your console-created VPC required navigating multiple screens. Terraform replaces that entire process with a single command.

  • In your terminal, make sure you are still inside your project directory (the folder containing main.tf).
  • Tear down all five resources by running this command:
terraform destroy
  • Terraform will show a plan of all five resources marked for destruction, then prompt you with a confirmation message.
  • Type yes and press Enter to confirm.

What does this command do?

terraform destroy reads your main.tf file and your Terraform state, then removes every resource it previously created. It calculates the correct order to delete things so nothing breaks mid-teardown.

The confirmation prompt requires you to type the full word yes. Anything else (including just pressing Enter) cancels the operation.

  • Return to the AWS VPC Console in your browser.
  • Click Your VPCs in the left sidebar.
  • Confirm that my-terraform-vpc no longer appears in the list.

Still seeing the VPC in the console?

Make sure you typed yes at the confirmation prompt. If you pressed Enter without typing anything, Terraform cancelled the destroy.

Also try clicking the refresh icon in the VPC Console. The list does not auto-update.

help me figure out why my VPC still appears after terraform destroy

Observe the dependency order

Scroll up in your terminal output from the destroy command. Notice the order Terraform deleted things.

  • The route table association was destroyed first.
  • Then the route table.
  • Then the internet gateway.
  • Then the subnet.
  • Finally, the VPC itself was removed last.

Why does the order matter?

AWS will not let you delete a VPC that still has subnets or gateways attached. Similarly, you cannot remove a route table that still has an active association.

Terraform reads the references between your resource blocks (like aws_vpc.main.id inside your subnet block) and builds a dependency graph. When destroying, it walks that graph in reverse. You never have to think about the right order.

Compare console clicks to Terraform code

Think back to the full lifecycle you just experienced across both approaches.

What changed between the two approaches?

With the console, you clicked through 5+ screens to create your VPC, then navigated back to each resource individually to delete them. One missed resource and the delete fails.

With Terraform, one terraform apply creates everything and one terraform destroy removes everything. The configuration file is version-controlled, shareable, and repeatable. You could spin up this exact VPC a hundred times with the same command.

Your main.tf file is still on disk. Even though the cloud resources are gone, you can recreate everything by running terraform apply again at any time.

Secret mission

Add a Private Subnet in a Second Availability Zone

Your Terraform configuration currently defines a single public subnet. Real-world VPCs almost always have private subnets too, for databases and internal services that should never be directly reachable from the internet. In this mission, you will extend your existing code with a private subnet in a second Availability Zone and observe how Terraform handles the addition seamlessly.

Clean Up Your Resources

Clean Up Your Resources

This project uses only free AWS resources. VPCs, subnets, internet gateways, and route tables have no ongoing cost, so nothing is accumulating charges.

Decide whether to keep your resources for further experimentation or delete them entirely.

Resources you used:

  • VPC infrastructure (VPC, subnets, internet gateway, route table, route table association) on AWS.
  • IAM user with programmatic access key.
  • Local project directory containing main.tf.
  • Terraform CLI (installed via apt).
  • AWS CLI v2 (installed via bundled installer).

Keep everything running

No action needed. Choose this if you plan to continue experimenting with Terraform and AWS networking.

  • Your VPC resources were already destroyed by terraform destroy in the previous step. No cloud resources remain.
  • Your IAM user, local project files, Terraform CLI, and AWS CLI stay on your machine ready for reuse.
  • Your AWS account remains active for future projects.

Pause - I'll come back to this later

Your cloud resources are already destroyed. Since VPC resources are free, there is nothing to pause. Your local files and tools remain ready for when you return.

  • No running processes to stop for this project.
  • Your main.tf file is ready to terraform apply again whenever you want to recreate the VPC.

Delete - I don't want to use this again

Remove all project resources and start fresh. Follow these steps to clean up everything.

Destroy any remaining VPC resources

If you already ran terraform destroy at the end of Step 5 or the Secret Mission, your cloud resources are already gone. If not, run the following from your project directory:

terraform destroy
Delete the IAM user
  • Open the IAM Console at https://console.aws.amazon.com/iam/.
  • In the left navigation pane, choose Users.
  • Select the checkbox next to the IAM user you created for this project.
  • Click Delete at the top of the page.
  • Type the username to confirm, then choose Delete.
Remove the local project directory
  • Delete the folder that contains your main.tf file by running:
rm -rf [[PROJECT_DIR="path/to/your/terraform-project-folder"]]
Uninstall Terraform CLI
  • Remove Terraform by running:
sudo apt remove terraform
Uninstall AWS CLI v2
  • Remove the AWS CLI symlinks and installation directory by running:
sudo rm /usr/local/bin/aws
sudo rm /usr/local/bin/aws_completer
sudo rm -rf /usr/local/aws-cli
  • Optionally, remove your stored AWS credentials by running:
rm -rf ~/.aws/

Why remove ~/.aws?

The ~/.aws/ folder contains your AWS access key ID and secret access key. If you no longer need CLI access to AWS, removing it prevents stale credentials from being used accidentally.

If you plan to use other AWS tools or keep your AWS account for future projects, skip this step.

That's a Wrap!

That's a Wrap!

Nice work! You just built a complete VPC on AWS two different ways and proved that every console click has a matching line of Terraform code.

You've learned how to:

  • Build a VPC with a public subnet through the AWS Console and explore the visual Resource Map to understand how networking components connect.
  • Write a Terraform configuration that recreates the same infrastructure as code, mapping each console resource to a resource block.
  • Run the full Terraform lifecycle (init, plan, apply, destroy) to create and tear down real AWS infrastructure in seconds.
  • Secret Mission: Added a private subnet in a second Availability Zone and observed how Terraform handles incremental changes with a single plan and apply.

Ready to quiz yourself?