Deploy a VPC with Terraform on AWS

Write Terraform code to deploy a VPC, subnet, and EC2 web server on AWS.

Introduction

30 Second Summary

Every time you click a button on a website, your request travels through a network of servers, firewalls, and routing rules that someone had to set up. Cloud engineers build these networks not by clicking through dashboards, but by writing code that creates infrastructure automatically.

In this project, you will write Terraform code that deploys a complete VPC networking environment and a live web server on AWS. You'll visit a public IP address in your browser and see a page that your code created from scratch.

What You'll Build

A complete AWS networking stack and EC2 web server deployed entirely through HCL (HashiCorp Configuration Language) files.

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

  • A main.tf file defining a VPC, subnet, internet gateway, route table, and security group.
  • A running web server accessible from any browser via a public IP address.
  • Hands-on experience with the full Terraform workflow including init, plan, apply, and destroy.
  • Secret Mission: Add a second EC2 instance in a private subnet with no internet access, demonstrating public vs. private networking patterns.

Are there any prerequisites?

You'll need an AWS account with the AWS CLI already installed and configured (access keys set up), VS Code installed, and basic familiarity with using a terminal.

Create the Terraform Project Structure

Your tools are ready. Terraform is installed, your AWS CLI is connected to your account, and VS Code has the Terraform extension for syntax highlighting.

Every Terraform project starts with a configuration file that tells Terraform which cloud provider to use and where to find credentials. In this step, you'll create that foundation file and initialize the project so Terraform can download the necessary provider plugin.

In this step, get ready to:
  • Create a project directory on your Desktop.
  • Write main.tf with the Terraform and AWS provider configuration.
  • Run terraform init to download the AWS provider plugin.
Create the project directory and open it in VS Code

You need a dedicated folder for your Terraform project. All your configuration files and the state Terraform generates will live here.

  • Open VS Code's integrated terminal by pressing Ctrl+` (backtick key, usually above Tab).
  • Move to your Desktop by running this command:
cd ~/Desktop
  • Create your project folder by running this command:
mkdir terraform-vpc-project
  • Confirm the folder exists by running:
ls

You should see terraform-vpc-project in the output.

  • In VS Code, click File in the top menu bar.
  • Click Open Folder.
  • Navigate to your Desktop, select the terraform-vpc-project folder, and click Select Folder.

VS Code reloads with your project folder as the workspace. You should see terraform-vpc-project in the Explorer sidebar on the left.

Don't see the folder in the file browser?

Make sure you're looking on your Desktop. If your terminal printed an error when you ran mkdir, the folder may not have been created. Re-run the mkdir terraform-vpc-project command and try again.

Help me find my terraform-vpc-project folder

Write the Terraform and provider configuration

Terraform reads .tf files written in HCL (HashiCorp Configuration Language). Your first file tells Terraform two things: which provider plugin to download, and which region to deploy resources in.

  • In VS Code's Explorer sidebar, right-click in the empty space below the folder name.
  • Click New File.
  • Type main.tf and press Enter.
  • Paste the following code into main.tf:
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 6.0"
    }
  }

  required_version = ">= 1.15.0"
}

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

What does this code do?

  • The terraform block declares which providers your project needs. Here you're telling Terraform to download the AWS provider from hashicorp/aws with a version compatible with 6.0.
  • The required_version line ensures anyone running this project has Terraform 1.15.0 or higher installed.
  • The provider "aws" block sets the default region to us-east-1. Terraform automatically reads your AWS credentials from the shared credentials file that the AWS CLI configured earlier.
  • Save main.tf by pressing Ctrl+S.

Seeing red squiggly lines in the file?

If the Terraform extension highlights syntax errors, double-check that you copied the entire code block including the closing braces. Every opening { needs a matching }.

Help me fix syntax errors in my main.tf file

✔️ Awesome, I've got everything!

Great. Double check you've saved main.tf before moving on to initialization.

ⓧ I'd like to double check the full code

Here is the complete main.tf file at this point:

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

  required_version = ">= 1.15.0"
}

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

Before Terraform can manage any infrastructure, it needs to download the provider plugin you declared. The terraform init command handles this setup.

  • Open VS Code's integrated terminal by pressing Ctrl+` (if it's not already open).
  • Download the AWS provider plugin by running this command:
terraform init

What does terraform init do?

This command reads your main.tf file, finds the required_providers block, and downloads the matching provider plugin from the Terraform Registry. It stores the plugin in a hidden .terraform/ directory inside your project.

It also creates a .terraform.lock.hcl file that locks the exact provider version. This ensures anyone else running your project gets the same provider version you used.

You should see output ending with the message Terraform has been successfully initialized! followed by a note about running terraform plan next.

  • Confirm the provider was downloaded by running:
ls .terraform/providers

You should see a registry.terraform.io folder listed, which contains the downloaded AWS provider plugin.

Seeing an error about provider packages?

If you see an error mentioning provider packages or network issues, check your internet connection. The terraform init command needs to reach the Terraform Registry to download the AWS provider.

If you see an error about no configuration files, make sure your terminal is inside the terraform-vpc-project folder. Run pwd to check your current directory.

Help me fix my terraform init error

Your project structure is set. Terraform knows which provider to use, which region to target, and where to find your AWS credentials. Next up, you'll write the VPC and networking configuration that Terraform will deploy.

Define the VPC and Networking

Your Terraform project is initialized and connected to AWS. Now it's time to define the actual cloud infrastructure you want to create.

In this step, you'll write HCL code that describes a complete networking layer on AWS. This includes a VPC, a public subnet, an internet gateway, and the route table that connects them all together.

In this step, get ready to:
  • Define a VPC, public subnet, and internet gateway in HCL.
  • Create a route table to direct internet traffic.
  • Preview your infrastructure plan with terraform plan.
Write HCL for the VPC, subnet, and internet gateway

Every AWS resource you deploy needs to live inside a network. A VPC is your own isolated section of the AWS cloud where you control the IP addresses, subnets, and routing.

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

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

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

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

# --- Internet Gateway ---
resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id

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

What does this code do?

  • aws_vpc "main" creates a Virtual Private Cloud with the IP range 10.0.0.0/16, giving you over 65,000 available addresses.
  • aws_subnet "public" carves out a smaller network (10.0.1.0/24, 256 addresses) inside the VPC. map_public_ip_on_launch = true means any instance launched here gets a public IP automatically.
  • aws_internet_gateway "main" attaches an internet gateway to the VPC so resources inside can reach the public internet.

What is a CIDR block?

A CIDR block defines a range of IP addresses using a base address and a prefix length. For example, 10.0.0.0/16 means "all addresses from 10.0.0.0 to 10.0.255.255" (the first 16 bits are fixed).

The smaller the prefix number, the larger the network. A /16 gives you 65,536 addresses, while a /24 gives you 256.

  • Save main.tf.
  • You won't see changes in AWS yet. The next chunk adds the route table that connects everything to the internet.
Create the route table and associate it with the subnet

A subnet alone can't reach the internet. You need a route table that tells traffic where to go, plus an association that links the table to your subnet.

  • In main.tf, add the following code below the internet gateway block:
# --- Route Table ---
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 = "terraform-public-rt"
  }
}

# --- Route Table Association ---
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?

  • aws_route_table "public" creates a routing rule that sends all outbound traffic (0.0.0.0/0 means "any destination") through the internet gateway.
  • aws_route_table_association "public" links this route table to your public subnet. Without this association, the subnet uses the VPC's default route table which has no internet route.
  • Save main.tf.

Seeing red underlines in VS Code?

If VS Code shows errors in your HCL, make sure each resource block has matching opening and closing braces. Also confirm you saved the file after your previous edits.

help me fix syntax errors in my Terraform main.tf file

✔️ Awesome, I've got everything!

Great. Double check you've saved main.tf before running the plan in the next substep.

ⓧ I'd like to double check the full code

Here is the complete main.tf so far. Compare your file against this:

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

  required_version = ">= 1.15.0"
}

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

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

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

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

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

# --- Internet Gateway ---
resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id

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

# --- Route Table ---
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 = "terraform-public-rt"
  }
}

# --- Route Table Association ---
resource "aws_route_table_association" "public" {
  subnet_id      = aws_subnet.public.id
  route_table_id = aws_route_table.public.id
}
Preview the infrastructure with terraform plan

Before deploying anything, Terraform lets you preview exactly what it will create. The terraform plan command compares your configuration to the current state and shows what changes are needed.

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

Terraform will list each resource it plans to create, marked with a + create symbol. At the bottom of the output, you should see:

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

What are the 5 resources?

  • aws_vpc.main (the VPC itself).
  • aws_subnet.public (the public subnet).
  • aws_internet_gateway.main (the gateway to the internet).
  • aws_route_table.public (the routing rules).
  • aws_route_table_association.public (links the route table to the subnet).

Seeing errors instead of a plan?

If you see a syntax error, check that every resource block in main.tf has matching opening and closing braces. A missing } is the most common culprit.

If you see a provider error, confirm you ran terraform init successfully in the previous step. You can run it again safely.

help me fix my terraform plan errors

Your networking blueprint is ready. Next up, you'll add a security group and an EC2 instance, then deploy everything to AWS with a single command.

Deploy the EC2 Web Server

Your networking blueprint is locked in. Terraform knows exactly which VPC, subnet, internet gateway, and route table to create.

Now it's time to deploy the actual server. You'll add a security group (the firewall rules that control who can reach your server), an EC2 instance running a web page, and an outputs file that tells you the public IP address to visit.

In this step, get ready to:
  • Add a security group that allows HTTP traffic on port 80.
  • Define an EC2 instance with a startup script that installs a web server.
  • Deploy all resources with terraform apply and visit your live page.
Add the security group

Without a security group, your EC2 instance blocks all incoming traffic by default. You need to explicitly open port 80 (HTTP) so browsers can reach the web server.

  • In VS Code, open main.tf and scroll to the bottom of the file (below the aws_route_table_association resource).
  • Add the following security group resource:
# --- Security Group ---
resource "aws_security_group" "web" {
  name        = "terraform-web-sg"
  description = "Allow HTTP inbound traffic"
  vpc_id      = aws_vpc.main.id

  ingress {
    description = "HTTP from anywhere"
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "terraform-web-sg"
  }
}

What does this code do?

The ingress block opens port 80 for inbound TCP traffic from any IP address (0.0.0.0/0). This lets browsers connect to your web server.

The egress block allows all outbound traffic (protocol -1 means "all protocols"). Your server needs outbound access to download packages during setup.

  • Save main.tf.
  • You won't see a change yet. The next chunk defines the EC2 instance that uses this security group.
Define the EC2 instance

Your EC2 instance needs two things: an AMI (the machine image that determines the operating system) and a startup script that installs the web server software.

  • In main.tf, add the following code below the security group you just created:
# --- EC2 Instance ---
data "aws_ami" "amazon_linux_2023" {
  most_recent = true
  owners      = ["amazon"]

  filter {
    name   = "name"
    values = ["al2023-ami-2023.*-x86_64"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }
}

resource "aws_instance" "web" {
  ami                    = data.aws_ami.amazon_linux_2023.id
  instance_type          = "t2.micro"
  subnet_id              = aws_subnet.public.id
  vpc_security_group_ids = [aws_security_group.web.id]

  user_data = <<-EOF
              #!/bin/bash
              dnf update -y
              dnf install -y httpd
              systemctl start httpd
              systemctl enable httpd
              echo "<h1>Hello from Terraform!</h1><p>This server was deployed with Infrastructure as Code.</p>" > /var/www/html/index.html
              EOF

  tags = {
    Name = "terraform-web-server"
  }
}

What does this code do?

The data "aws_ami" block is a data source that automatically looks up the latest Amazon Linux 2023 AMI. You never need to hardcode an AMI ID this way.

The aws_instance block creates a t2.micro instance (Free Tier eligible) and places it in your public subnet with the security group attached.

The user_data script runs once at first boot. It installs Apache (httpd), starts the service, and writes a simple HTML page.

  • Save main.tf.
  • You won't see a visible change yet. The next substep deploys everything with terraform apply.

Seeing red squiggles in VS Code?

If the Terraform extension highlights errors, make sure the data block appears before the resource "aws_instance" block. The instance references data.aws_ami.amazon_linux_2023.id, so the data source must be declared first.

Also confirm there is no typo in vpc_security_group_ids. It expects a list (square brackets), not a bare string.

help me fix Terraform syntax errors in my main.tf

✔️ Awesome, I've got everything!

Great. Double check you've saved main.tf and move on to the next substep.

ⓧ I'd like to double check the full code

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

  required_version = ">= 1.15.0"
}

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

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

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

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

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

# --- Internet Gateway ---
resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id

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

# --- Route Table ---
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 = "terraform-public-rt"
  }
}

# --- Route Table Association ---
resource "aws_route_table_association" "public" {
  subnet_id      = aws_subnet.public.id
  route_table_id = aws_route_table.public.id
}

# --- Security Group ---
resource "aws_security_group" "web" {
  name        = "terraform-web-sg"
  description = "Allow HTTP inbound traffic"
  vpc_id      = aws_vpc.main.id

  ingress {
    description = "HTTP from anywhere"
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "terraform-web-sg"
  }
}

# --- EC2 Instance ---
data "aws_ami" "amazon_linux_2023" {
  most_recent = true
  owners      = ["amazon"]

  filter {
    name   = "name"
    values = ["al2023-ami-2023.*-x86_64"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }
}

resource "aws_instance" "web" {
  ami                    = data.aws_ami.amazon_linux_2023.id
  instance_type          = "t2.micro"
  subnet_id              = aws_subnet.public.id
  vpc_security_group_ids = [aws_security_group.web.id]

  user_data = <<-EOF
              #!/bin/bash
              dnf update -y
              dnf install -y httpd
              systemctl start httpd
              systemctl enable httpd
              echo "<h1>Hello from Terraform!</h1><p>This server was deployed with Infrastructure as Code.</p>" > /var/www/html/index.html
              EOF

  tags = {
    Name = "terraform-web-server"
  }
}
Create outputs.tf and deploy

Terraform can display important values after a deployment completes. You define these in a separate outputs.tf file so the public IP address prints directly to your terminal.

  • Create a new file called outputs.tf in the same folder as main.tf.
  • Add the following output definitions:
output "web_server_public_ip" {
  description = "Public IP address of the web server"
  value       = aws_instance.web.public_ip
}

output "web_server_url" {
  description = "URL to access the web server"
  value       = "http://${aws_instance.web.public_ip}"
}

output "vpc_id" {
  description = "ID of the VPC"
  value       = aws_vpc.main.id
}

What does this code do?

Each output block tells Terraform to print a value to the terminal after terraform apply finishes.

The web_server_public_ip output gives you the raw IP. The web_server_url output wraps it in a clickable http:// URL. The vpc_id output confirms which VPC was created.

  • Save outputs.tf.

✔️ Awesome, I've got everything!

Great. Double check you've saved outputs.tf and continue below.

ⓧ I'd like to double check the full code

output "web_server_public_ip" {
  description = "Public IP address of the web server"
  value       = aws_instance.web.public_ip
}

output "web_server_url" {
  description = "URL to access the web server"
  value       = "http://${aws_instance.web.public_ip}"
}

output "vpc_id" {
  description = "ID of the VPC"
  value       = aws_vpc.main.id
}
  • Deploy all your infrastructure by running this command in your terminal:
terraform apply

What happens when you run this?

Terraform shows you the full execution plan (similar to terraform plan) and then prompts you for confirmation. You should see 7 resources to add (VPC, subnet, internet gateway, route table, route table association, security group, and EC2 instance).

When you see the prompt asking if you want to perform these actions, type yes and press Enter. Terraform will create all resources in your AWS account.

  • Wait for the apply to complete. This takes 30-60 seconds while AWS provisions the EC2 instance.
  • Once complete, Terraform prints the outputs. Copy the web_server_url value from your terminal.
  • Paste the URL into your browser and press Enter.

You should see a page displaying "Hello from Terraform!" with the subtitle "This server was deployed with Infrastructure as Code."

Page not loading in the browser?

Make sure you're using http:// (not https://). The security group only allows HTTP on port 80, not HTTPS on port 443.

If the page times out, the EC2 instance may still be booting and running the user_data script. Wait 1-2 minutes and try again.

If it still doesn't work, verify that map_public_ip_on_launch = true is set on your aws_subnet.public resource. Without this, the instance won't receive a public IP.

help me debug why my Terraform-deployed web server is not accessible in the browser

Why is this free?

The t2.micro instance type is Free Tier eligible for AWS accounts created before July 15, 2025. You get 750 hours per month at no charge. Since you'll destroy these resources shortly, you won't incur any cost.

Your web server is live and accessible from anywhere in the world. Next up, you'll learn how to tear everything down cleanly with a single command.

Destroy All Resources

Your web server is live and accessible from anywhere on the internet. You proved that Terraform can build real infrastructure from code.

Now it's time to prove the other half of Infrastructure as Code: tearing everything down just as easily as you built it. One command will destroy all seven resources and leave your AWS account clean with zero charges.

In this step, get ready to:
  • Destroy all AWS resources with a single Terraform command.
  • Confirm zero charges on the AWS Free Tier dashboard.
  • Review the Terraform state file to understand how Terraform tracks infrastructure.
Run terraform destroy to tear down all infrastructure

The terraform destroy command reads your state file, identifies every resource Terraform created, and deletes them all in the correct dependency order.

  • In your VS Code terminal, run the destroy command:
terraform destroy

What happens when you run this?

Terraform will show you a destruction plan listing every resource it intends to delete. This is similar to how terraform plan previews creations, but in reverse.

You will see a confirmation prompt asking you to type yes to proceed. Only typing yes will confirm the destruction. Any other input cancels the operation.

  • When prompted, type yes and press Enter to confirm.

Terraform will destroy each resource one by one. You should see a final message: Destroy complete! Resources: 7 destroyed.

Seeing a dependency error?

If Terraform reports a dependency conflict, run the command again. Terraform may need a second pass to resolve ordering in rare cases.

If you see a permissions error, confirm your AWS CLI credentials are still valid by running aws sts get-caller-identity.

Help me debug a terraform destroy error

Verify resources are gone in the AWS Console

The terminal says everything is destroyed, but you should always verify in the AWS Console to build confidence that Terraform did its job.

  • Open the AWS Console in your browser.
  • In the top search bar, type VPC and select the VPC service.
  • Click Your VPCs in the left sidebar.
  • Confirm that terraform-vpc is no longer listed. You should only see your account's default VPC.
  • Go back to the search bar, type EC2, and open the EC2 service.
  • Click Instances in the left sidebar.
  • Confirm that terraform-web-server is either gone or shows a terminated state.

Why verify in the Console?

The AWS Console is the ground truth for what exists in your account. Building the habit of verifying after a destroy ensures you never leave orphaned resources running up charges.

Confirm no charges on the Free Tier dashboard

Your EC2 instance ran for only a few minutes. That's well within the Free Tier's 750 hours per month allowance for t2.micro instances.

  • In the AWS Console search bar, type Billing and select Billing and Cost Management.
  • Click Free Tier in the left sidebar.
  • Confirm that your EC2 usage shows a small fraction of the 750-hour monthly allowance. You should see no charges.

What about VPC networking costs?

VPCs, subnets, internet gateways, route tables, and security groups are all free. AWS only charges for data transfer and running compute. Since you destroyed the t2.micro instance within minutes, your total cost for this project is $0.

Review the Terraform state file

Terraform tracks every resource it manages in a state file. After destroying everything, the state file becomes a record of what used to exist.

  • In VS Code, open the terraform.tfstate file in your project folder.

You should see a JSON file with an empty resources array. This confirms Terraform knows that no infrastructure exists anymore.

What is the state file?

The terraform.tfstate file is how Terraform maps your code to real-world resources. Before the destroy, it contained the IDs of your VPC, subnet, EC2 instance, and every other resource.

When you ran terraform destroy, Terraform read this file to know which resources to delete. Now that they're gone, the resources list is empty. If you were to run terraform apply again, Terraform would recreate everything from scratch.

Never commit state files to Git

State files can contain sensitive data like IP addresses and resource IDs. In team environments, state is stored remotely (in S3 or Terraform Cloud). For this project, keeping it local is fine since you destroyed everything.

Secret mission

Add a Private Subnet Instance

In real-world cloud architectures, not every server should be reachable from the internet. Databases, internal APIs, and backend workers live in private subnets with no public route. Can you add a second EC2 instance in a private subnet and prove that it is completely isolated from the public internet?

Clean Up Your Resources

Clean Up Your Resources

This project runs on the AWS Free Tier, and you already destroyed all AWS resources with terraform destroy in the previous step. No cloud resources are incurring charges.

Decide whether to keep your local project files for future redeployment, or remove everything from your machine entirely.

Resources you used:

  • AWS resources (VPC, subnets, internet gateway, route table, security groups, EC2 instances) — already destroyed via terraform destroy.
  • Local project files (main.tf, outputs.tf, .terraform/ directory, terraform.tfstate files).
  • Terraform CLI (v1.15.3 binary installed on your system).
  • HashiCorp Terraform VS Code extension.

Keep everything running

No action needed. Choose this if you plan to redeploy or extend this project later.

  • Your Terraform project files stay on your Desktop, ready for redeployment anytime with terraform apply.
  • The Terraform CLI and VS Code extension remain installed for future projects.
  • If you redeploy later, the t2.micro instance is covered under the AWS Free Tier (750 hours/month for accounts created before July 15, 2025). VPC networking constructs (VPC, subnets, internet gateway, route tables, security groups) are always free.

Pause - I'll come back to this later

Your infrastructure is already destroyed. Your project files remain on disk for when you want to pick this back up.

  • No ongoing AWS charges. All cloud resources were removed with terraform destroy.
  • When you return, run terraform apply from your project folder to redeploy everything.
  • Terraform will recreate the full infrastructure from your main.tf file.

Delete - I don't want to use this again

Remove all project resources from your machine and start fresh.

  • AWS resources: Already destroyed. No action needed.
  • Delete your local project folder by opening PowerShell and running:
cd ~/Desktop
Remove-Item -Recurse -Force [[PROJECT_FOLDER="your Terraform project folder name"]]
  • If you installed Terraform via Chocolatey, uninstall it by running:
choco uninstall terraform
  • If you installed Terraform manually (binary download), delete the terraform.exe file from the folder where you placed it, and remove that folder from your system PATH.
  • Uninstall the HashiCorp Terraform extension in VS Code by clicking the Extensions icon in the left sidebar, finding HashiCorp Terraform, and clicking Uninstall.

What about your AWS account?

Your AWS account itself has no ongoing cost from this project. All infrastructure was destroyed. You do not need to delete your AWS account unless you want to.

Nice Work!

Nice Work!

You just deployed real AWS infrastructure using Terraform. That's not a lab exercise. That's what cloud engineers do every day.

You've learned how to:

  • Write HCL to define a complete VPC networking stack with subnets, route tables, and security groups.
  • Deploy an EC2 web server accessible from the public internet using Infrastructure as Code.
  • Use the full terraform init, plan, apply, and destroy workflow to manage cloud resources programmatically.
  • Secret Mission: Added a private subnet to demonstrate network isolation patterns.

Ready to quiz yourself?