Deploy a Web Server on AWS with Terraform

Provision a VPC, security group, and EC2 web server on AWS using Terraform.

Introduction

30 Second Summary

Every time you set up a server by clicking through a cloud console, you lose that work the moment you close the browser. There is no record of what you built, no way to recreate it instantly, and no way to tear it all down with one command.

In this project, you will write Terraform configuration files that provision a complete networking stack and web server on AWS, deploy everything with a single command, and destroy it just as easily.

What You'll Build

A Terraform project that defines a VPC, public subnet, internet gateway, security group, and EC2 instance running Apache on AWS.

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

  • A complete Infrastructure as Code project with provider configuration, networking resources, and compute resources.
  • Hands-on experience with the full Terraform workflow: write configuration, initialize, plan, apply, and destroy.
  • A live web server accessible from the internet, deployed entirely through code.
  • Secret Mission: Parameterize your configuration with Terraform variables for reusability.

Are there any prerequisites?

No prior experience with Terraform or AWS is needed. This project walks you through installing all required tools and creating an AWS account from scratch.

Install Terraform and AWS CLI

Before you can deploy infrastructure with code, you need two tools on your machine. Terraform translates your configuration files into real cloud resources. The AWS CLI lets Terraform authenticate with your AWS account.

In this step, you will install both tools on Windows and verify they are working from the command line.

In this step, get ready to:
  • Install Terraform and add it to your system PATH.
  • Install the AWS CLI using the official MSI installer.
  • Verify both tools return version information from Command Prompt.
Download and install Terraform

Terraform is a single executable file that you download, place in a folder, and tell Windows where to find it. Once it is on your PATH, you can run Terraform commands from any directory.

  • Press the Windows key to open your search bar.
  • Type Command Prompt and press Enter to open it.
  • Check if Terraform is already installed by running this command:
terraform -version

✔️ I see version 1.2 or higher

Your Terraform installation meets the project requirements. You can skip ahead to the AWS CLI substep below.

ⓧ I see an older version

You need Terraform 1.2 or higher for this project. Follow the steps below to install the latest version, which will replace your current one.

  • Visit the Terraform install page in your browser.
  • Under the Windows section, click the AMD64 binary download link for version 1.15.7.
  • Extract the downloaded zip file. Move terraform.exe into the same folder your old version was in (check your existing PATH entries to find it).
  • Close and reopen Command Prompt, then run terraform -version again to confirm you see 1.15.7.

Still seeing the old version?

Make sure you replaced the old terraform.exe file, not placed the new one in a different folder. Windows uses whichever copy it finds first in the PATH.

help me figure out why my Terraform version isn't updating after I replaced the binary

ⓧ Command not found

Terraform is not installed yet. Follow the steps below to set it up.

  • Visit the Terraform install page in your browser.
  • Under the Windows section, click the AMD64 binary download link for version 1.15.7.
  • Create a folder called C:\terraform on your computer.
  • Extract the zip file and move terraform.exe into C:\terraform.

Now you need to tell Windows where to find the Terraform binary by adding it to your system PATH.

  • Press the Windows key, type Environment Variables, and select Edit the system environment variables.
  • In the System Properties window, click Environment Variables.
  • Under System variables, find the row called Path and select it.
  • Click Edit.
  • Click New and type C:\terraform.
  • Click OK on all three open windows to save your changes.

What is the system PATH?

The PATH is a list of folders that Windows searches through when you type a command. By adding C:\terraform to this list, Windows can find terraform.exe no matter which folder your Command Prompt is currently in.

  • Close your current Command Prompt window completely.
  • Open a new Command Prompt (press the Windows key, type Command Prompt, press Enter).
  • Verify the install by running:
terraform -version

You should see output showing Terraform v1.15.7.

Still seeing 'not recognized'?

Make sure you opened a new Command Prompt after editing the PATH. Existing windows do not pick up PATH changes.

Double-check that terraform.exe is directly inside C:\terraform (not in a subfolder like C:\terraform\terraform_1.15.7_windows_amd64\).

help me troubleshoot why terraform -version is not recognized in my Command Prompt on Windows

Install the AWS CLI

The AWS CLI is a command-line tool that lets you interact with AWS services. Terraform uses the credentials stored by the AWS CLI to authenticate with your account.

  • In your Command Prompt, check if the AWS CLI is already installed by running:
aws --version

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

Your AWS CLI version 2 is already installed. You can skip ahead to the verification substep below.

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

You have AWS CLI version 1 installed. Version 1 is end-of-support and this project requires version 2. The version 2 MSI installer will overwrite your existing installation.

  • Download the AWS CLI v2 MSI installer by running this command in Command Prompt:
msiexec.exe /i https://awscli.amazonaws.com/AWSCLIV2.msi

What does this command do?

The msiexec.exe tool is the Windows installer engine. It downloads and runs the official AWS CLI v2 package, which replaces your version 1 installation automatically.

  • Follow the installer prompts and accept the defaults.
  • Close and reopen Command Prompt after the installation finishes.
  • Run aws --version again to confirm you now see aws-cli/2. at the start of the output.

Installer won't start?

If you see an access denied error, try downloading the MSI file directly from https://awscli.amazonaws.com/AWSCLIV2.msi in your browser and double-clicking it to run.

help me install AWS CLI v2 on Windows when msiexec gives an access error

ⓧ Command not found

The AWS CLI is not installed yet. You will install it using the official MSI installer.

  • Install the AWS CLI by running this command in Command Prompt:
msiexec.exe /i https://awscli.amazonaws.com/AWSCLIV2.msi

What does this command do?

The msiexec.exe tool is the Windows installer engine. It downloads and runs the official AWS CLI v2 package directly from Amazon's servers. The installer handles adding the aws command to your PATH automatically.

  • Follow the installer prompts and accept the defaults.
  • Close and reopen Command Prompt after the installation finishes.
  • Verify the install by running:
aws --version

You should see output starting with aws-cli/2. followed by version details.

Still not recognized after install?

Make sure you closed and reopened Command Prompt after the installer finished. The aws command will not be available in windows that were open during installation.

help me figure out why aws --version is not recognized after running the MSI installer

Verify both tools

With both installations complete, run a final check to confirm everything is working from the same Command Prompt window.

  • Verify Terraform by running:
terraform -version
  • Confirm the output shows v1.15.7.
  • Verify the AWS CLI by running:
aws --version
  • Confirm the output starts with aws-cli/2. followed by version and platform info.

What should I see?

The terraform -version output shows the Terraform version number. The aws --version output shows the AWS CLI version, the Python version it bundles, your OS, and architecture.

Both commands returning version information (no errors) means your tools are installed correctly and accessible from the command line.

Your tools are installed and ready. Next up, you will create an AWS account and configure your credentials so Terraform can provision resources on your behalf.

Create an AWS Account and Configure Credentials

You have Terraform and the AWS CLI installed. Now you need somewhere to deploy your infrastructure.

In this step, you will create an AWS account, set up a dedicated IAM user for Terraform, and configure the AWS CLI so Terraform can authenticate with your account.

In this step, get ready to:
  • Create a new AWS account.
  • Create an IAM user with programmatic access.
  • Configure the AWS CLI with your credentials.
Create a new AWS account

AWS is the cloud provider where Terraform will create your infrastructure resources. You need an account before you can provision anything.

  • Open your browser and go to https://aws.amazon.com.
  • Click Create an AWS Account in the top-right corner.
  • Enter your email address, choose an account name, and click Verify email address.
  • Complete the email verification step by entering the code sent to your inbox.
  • Follow the on-screen prompts to set a root password, enter contact information, and add a payment method.
  • Choose a support plan. The free plan is fine for this project.

What about cost?

New AWS accounts created after July 15, 2025 receive $100 in credits at sign-up and can earn up to $100 more by completing activities. All resources in this project are covered by these credits.

You will destroy all resources at the end of the project, so nothing continues running after you finish.

Create an IAM user with access keys

Instead of using your root account (which has unlimited access), you will create a dedicated IAM user for Terraform. This is a security best practice that limits blast radius if credentials are ever exposed.

  • Sign in to the AWS Management Console at https://console.aws.amazon.com using your root email and password.
  • In the top search bar, type IAM and select IAM from the results.
  • In the left navigation pane, click Users.
  • Click Create user.
  • For User name, type terraform-user.
  • Click Next.
  • On the Set permissions page, select Attach policies directly.
  • In the search box, type AdministratorAccess and check the box next to the AdministratorAccess policy.
  • Click Next, then click Create user.

Now you need to create access keys so Terraform can authenticate as this user.

  • Click on the terraform-user username to open the user details page.
  • Select the Security credentials tab.
  • Scroll down to the Access keys section and click Create access key.
  • On the best practices page, select Command Line Interface (CLI) as the use case.
  • Check the confirmation checkbox at the bottom, then click Next.
  • Click Create access key.
  • Click Download .csv file to save your Access Key ID and Secret Access Key to a file on your computer.

This is your only chance to download the secret key

AWS only shows the Secret Access Key once at this screen. If you close this page without downloading the .csv file, you will need to delete this key and create a new one.

Store this file in a secure location. Do not share it or commit it to version control.

Why use an IAM user instead of the root account?

The root account has unrestricted access to everything in your AWS account, including billing and account deletion. Creating a separate IAM user for Terraform limits what these credentials can do if they are accidentally exposed.

In production environments, you would use even more restrictive policies. For this learning project, AdministratorAccess keeps things simple while still following the separate-user pattern.

Configure the AWS CLI

Terraform's AWS provider reads credentials from the same shared credentials file that the AWS CLI uses. By running aws configure, you store your access keys where Terraform can find them automatically.

  • Return to Command Prompt and run the configure command:
aws configure

The command prompts you for four values. Enter them one at a time as follows:

  • For AWS Access Key ID, open the .csv file you downloaded and paste the Access Key ID value.
  • For AWS Secret Access Key, paste the Secret Access Key value from the same .csv file.
  • For Default region name, type us-west-2.
  • For Default output format, type json.

What does aws configure do?

This command stores your credentials in a file at %USERPROFILE%\.aws\credentials on Windows. Terraform's AWS provider automatically reads this file when it needs to authenticate API calls to AWS.

The region us-west-2 is where your infrastructure will be created. The json output format makes CLI responses easier to read.

Now verify that your credentials are working correctly.

  • Confirm your identity by running:
aws sts get-caller-identity

You should see JSON output containing your account ID, user ARN, and user ID. It looks similar to this:

{
    "UserId": "AIDASAMPLEUSERID",
    "Account": "123456789012",
    "Arn": "arn:aws:iam::123456789012:user/terraform-user"
}

What should I see?

The Account field shows your 12-digit AWS account number. The Arn field should end with user/terraform-user, confirming that Terraform will authenticate as the IAM user you just created.

Seeing an error instead of your account info?

If you see a message about invalid credentials, double-check that you pasted the Access Key ID and Secret Access Key exactly as they appear in the downloaded .csv file. Extra spaces or missing characters will cause authentication to fail.

If you get a 'command not found' error, close and reopen Command Prompt so it picks up the AWS CLI installation from the previous step.

Help me troubleshoot my aws sts get-caller-identity error. I just ran aws configure with my terraform-user credentials and the command is failing.

Your AWS account is live and your CLI can authenticate. Next up, you will write your first Terraform configuration files that define the infrastructure you want to create.

Write Your Terraform Configuration

Your tools are installed and your AWS credentials are configured. Now it is time to write the code that defines your cloud infrastructure.

In this step, you will create three HCL configuration files that describe an entire networking stack and web server. When you run terraform apply later, Terraform reads these files and builds the matching resources in AWS.

In this step, get ready to:
  • Create a project directory and define provider requirements in terraform.tf.
  • Define a full VPC networking stack in main.tf.
  • Define a security group, AMI data source, and EC2 instance, plus an output file.
Create the project structure

Every Terraform project lives in its own directory. Terraform reads all .tf files in the current folder when you run commands.

  • Move to your Desktop by running this command:
cd %USERPROFILE%\Desktop
  • Create your project folder and move into it by running these commands:
mkdir learn-terraform-aws
cd learn-terraform-aws
  • Confirm the folder exists by running:
cd

You should see a path ending in learn-terraform-aws.

Not seeing the right path?

Make sure you ran both mkdir and cd as separate commands, not on the same line. If you see your home directory instead, re-run cd %USERPROFILE%\Desktop\learn-terraform-aws.

help me navigate to my learn-terraform-aws folder

Now open your code editor and open the learn-terraform-aws folder you just created on your Desktop.

  • Create a new file called terraform.tf in your code editor.
  • Paste the following code into terraform.tf:
# Define which providers this project needs
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.92"
    }
  }

  required_version = ">= 1.2"
}

What does this code do?

  • required_providers tells Terraform to download the AWS provider plugin from HashiCorp's registry.
  • version = "~> 5.92" means any version 5.92 or higher within major version 5.
  • required_version = ">= 1.2" ensures you are running Terraform 1.2 or newer.
  • Save terraform.tf.

✔️ Awesome, I've got everything!

Great. Double check you have saved your file before moving on.

ⓧ I'd like to double check the full code

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

  required_version = ">= 1.2"
}
Define the VPC networking resources

A VPC (Virtual Private Cloud) is your own isolated network inside AWS. Every resource you launch needs to live inside a VPC.

You will define the VPC, a public subnet, an internet gateway, and a route table. Together these let traffic flow from the internet to your future web server.

  • Create a new file called main.tf in your code editor.
  • Paste the following code into main.tf:
# Configure the AWS provider with our target region
provider "aws" {
  region = "us-west-2"
}

# Create an isolated virtual network
resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_hostnames = true

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

# Create a public subnet inside the VPC
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-west-2a"

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

# Attach an internet gateway so traffic can reach the internet
resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id

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

# Create a route table that sends all traffic to the internet gateway
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"
  }
}

# Link the route table to the public subnet
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?

  • provider "aws" tells Terraform to use the AWS provider and deploy resources in us-west-2. Terraform automatically reads your AWS CLI credentials, so no keys are needed here.
  • aws_vpc creates your own private network with 65,536 IP addresses (the /16 CIDR block).
  • aws_subnet carves out a smaller 256-address range inside the VPC. map_public_ip_on_launch = true gives each instance a public IP automatically.
  • aws_internet_gateway is the door between your VPC and the public internet.
  • aws_route_table with route 0.0.0.0/0 sends all outbound traffic through the internet gateway.
  • aws_route_table_association attaches that route table to the public subnet so instances there can reach the internet.
  • Save main.tf.

You will not see a change yet. The next substep adds the compute resources that use this network.

Seeing red squiggles in your editor?

Some code editors show warnings for .tf files before Terraform is initialized. This is normal. The warnings disappear after you run terraform init in the next step.

help me fix HCL errors in my main.tf file

Define the security group, AMI data source, and EC2 instance

With the network in place, you need three more pieces: a firewall rule (security group) that allows web traffic, a data source that finds the right server image, and the EC2 instance itself.

  • In main.tf, scroll to the bottom of the file (below the aws_route_table_association resource).
  • Add the following code at the end of main.tf:
# Allow inbound HTTP traffic on port 80
resource "aws_security_group" "web" {
  name   = "terraform-web-sg"
  vpc_id = aws_vpc.main.id

  ingress {
    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"
  }
}

# Find the latest Ubuntu 24.04 AMI from Canonical
data "aws_ami" "ubuntu" {
  most_recent = true

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd-gp3/ubuntu-noble-24.04-amd64-server-*"]
  }

  owners = ["099720109477"]
}

# Launch a web server using the Ubuntu AMI
resource "aws_instance" "web" {
  ami                    = data.aws_ami.ubuntu.id
  instance_type          = "t3.micro"
  subnet_id              = aws_subnet.public.id
  vpc_security_group_ids = [aws_security_group.web.id]

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

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

What does this code do?

  • aws_security_group acts as a firewall. The ingress block allows HTTP traffic on port 80 from anywhere. The egress block allows all outbound traffic.
  • data "aws_ami" queries AWS to find the latest Ubuntu 24.04 server image owned by Canonical (099720109477). Using a data source means your config always picks up the newest patched image.
  • aws_instance launches a t3.micro server in your public subnet. The user_data script runs on first boot to install Apache and write a simple HTML page.
  • Save main.tf.

✔️ 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

provider "aws" {
  region = "us-west-2"
}

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

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

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-west-2a"

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

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

  tags = {
    Name = "terraform-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 = "terraform-public-rt"
  }
}

resource "aws_route_table_association" "public" {
  subnet_id      = aws_subnet.public.id
  route_table_id = aws_route_table.public.id
}

resource "aws_security_group" "web" {
  name   = "terraform-web-sg"
  vpc_id = aws_vpc.main.id

  ingress {
    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"
  }
}

data "aws_ami" "ubuntu" {
  most_recent = true

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd-gp3/ubuntu-noble-24.04-amd64-server-*"]
  }

  owners = ["099720109477"]
}

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

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

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

Now create the output file that will display your server's public IP after deployment.

  • Create a new file called outputs.tf in your code editor.
  • Paste the following code into outputs.tf:
# Display the public IP after deployment
output "instance_public_ip" {
  description = "Public IP address of the web server"
  value       = aws_instance.web.public_ip
}

What does this output do?

Terraform outputs print values to your terminal after terraform apply finishes. This output extracts the public IP that AWS assigns to your EC2 instance, so you can paste it into a browser to visit your web server.

  • Save outputs.tf.

✔️ Awesome, I've got everything!

Great. Double check you have saved the file before moving on.

ⓧ I'd like to double check the full code

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

All three files are complete. Validate that Terraform can read them without syntax errors.

  • Switch back to your Command Prompt (which should still be inside learn-terraform-aws).
  • Validate your configuration by running:
terraform validate

You should see the message: Success! The configuration is valid..

Seeing an error instead of success?

  • Check for typos in resource references. Every aws_vpc.main.id reference must match the resource name exactly (case-sensitive).
  • Make sure all opening braces { have a matching closing brace }.
  • Verify you saved all three files (terraform.tf, main.tf, outputs.tf) before running the command.

help me fix a terraform validate error

Your configuration is validated and ready to deploy. Next up, you will run terraform init and terraform apply to turn this code into real running infrastructure.

Deploy and Verify Your Infrastructure

Your configuration files are written and validated. Terraform knows exactly what infrastructure you want, but nothing exists on AWS yet.

In this step, you'll run the full Terraform deployment workflow: initialize the project, preview the plan, apply it to create real resources, and then confirm your web server is live on the internet.

In this step, get ready to:
  • Download the AWS provider plugin with terraform init.
  • Deploy 7 AWS resources with terraform apply.
  • Verify your web server is live and accessible from the internet.
Initialize and plan

Before Terraform can create anything, it needs to download the provider plugin that knows how to talk to AWS. This is what terraform init does.

  • Download the AWS provider by running this command:
terraform init

What does this command do?

terraform init reads your terraform.tf file, finds the hashicorp/aws provider requirement, and downloads the matching plugin into a hidden .terraform directory. This only needs to run once per project (or when you change providers).

  • Confirm the output shows Terraform has been successfully initialized! near the bottom.

Seeing a provider error?

Make sure your terraform.tf file has the correct provider source (hashicorp/aws) and version constraint (~> 5.92). A typo in the source string is the most common cause.

Also check that your internet connection is active. Terraform downloads the plugin from the HashiCorp registry.

help me fix a terraform init error

Now that the provider is downloaded, you can preview what Terraform will create.

  • Preview the infrastructure changes by running:
terraform plan

What does terraform plan do?

terraform plan reads all your .tf files, connects to AWS using your configured credentials, and calculates the difference between what exists (nothing yet) and what you've defined. It shows a detailed preview without making any changes.

  • Confirm the output ends with Plan: 7 to add, 0 to change, 0 to destroy. at the bottom.

What are the 7 resources?

Terraform is planning to create:

  • A VPC (your private network).
  • A public subnet inside the VPC.
  • An internet gateway to connect the VPC to the internet.
  • A route table directing traffic to the internet gateway.
  • A route table association linking the subnet to the route table.
  • A security group allowing HTTP traffic on port 80.
  • An EC2 instance running Apache.

Plan shows errors instead of resources?

If you see an authentication error, run aws sts get-caller-identity to verify your AWS credentials are still configured. If that command fails, re-run aws configure with your Access Key ID and Secret Access Key.

If you see a syntax error, check the file and line number in the error message. Run terraform validate to pinpoint the issue.

help me fix my terraform plan error

Apply the configuration

The plan looks good. Now you'll tell Terraform to actually create those 7 resources on AWS.

  • Deploy your infrastructure by running:
terraform apply

Terraform asks for confirmation

After showing the same plan preview, Terraform prompts you to type yes and press Enter to confirm. This safety step prevents accidental changes to your infrastructure.

  • Type yes when prompted and press Enter.
  • Wait for creation to complete. This typically takes 30-60 seconds as AWS provisions your resources.
  • Confirm the output shows Apply complete! Resources: 7 added, 0 changed, 0 destroyed. followed by the instance_public_ip output value.

Save that IP address

The instance_public_ip value printed at the end is your web server's public IP address. You'll use it in the next substep to visit your live web page.

Apply failed partway through?

If you see a permissions error, your IAM user may not have the AdministratorAccess policy attached. Check the IAM console to confirm.

If you typed something other than yes (including Yes or y), Terraform cancels the apply. Run terraform apply again and type yes exactly.

help me fix a terraform apply failure

Verify the web server

Your infrastructure exists on AWS now. The EC2 instance is running Ubuntu, installing Apache, and serving your custom HTML page. Time to see it in action.

  • Copy the public IP address from the instance_public_ip output in your terminal.
  • Open your web browser and navigate to http:// followed by the IP address you copied.

You should see a page with the heading "Hello from Terraform!" and a paragraph that says "This web server was deployed using Infrastructure as Code."

Page not loading?

Give it 1-2 minutes. The EC2 instance needs time to boot and run the Apache installation script. Try refreshing after a short wait.

Make sure you're using http:// and not https:// in the URL. Your security group only allows traffic on port 80 (HTTP).

If it still doesn't load after a few minutes, check that your security group allows inbound traffic on port 80. Run terraform plan to see if there's any drift.

help me access my Terraform web server

  • Back in your terminal, view all the resources Terraform is managing by running:
terraform state list

What does this command show?

terraform state list prints every resource Terraform is tracking. You should see 7 entries matching the resources in your main.tf file: the VPC, subnet, internet gateway, route table, route table association, security group, and EC2 instance.

Terraform stores this state in a local terraform.tfstate file. This is how Terraform knows what it created and can update or destroy those resources later.

Your web server is live on the internet, deployed entirely through code. Next up, you'll learn how to tear it all down with a single command.

Destroy Your Infrastructure

Your web server is live and serving traffic from AWS. You proved that Terraform can create real cloud infrastructure from code.

Now it's time to prove the other half of the Infrastructure as Code lifecycle. With a single command, Terraform will destroy every resource it created and leave your AWS account clean.

In this step, get ready to:
  • Run terraform destroy to remove all 7 AWS resources.
  • Verify that your infrastructure is completely gone.
Run terraform destroy

Terraform tracks every resource it created in a state file. The terraform destroy command reads this state and removes each resource in the correct dependency order.

  • Remove all your AWS infrastructure by running this command:
terraform destroy

What happens next?

Terraform displays a destruction plan listing all 7 resources marked with a - prefix. It then asks for confirmation.

When you see the prompt "Do you really want to destroy all resources?", type yes and press Enter to confirm. The destruction takes about 30-60 seconds to complete.

  • Wait for the destruction to finish. You should see Destroy complete! Resources: 7 destroyed. in your terminal.

Seeing an error instead of the destroy plan?

  • If you see a credentials error, your AWS session may have expired. Run aws configure again to refresh your credentials, then retry terraform destroy.
  • If a resource fails to delete due to a dependency, run terraform destroy again. Terraform will retry destroying the remaining resources.

Why is terraform destroy failing for me?

Verify cleanup

It's good practice to double-check that all resources are actually gone. You'll confirm from two angles: the browser and the AWS console.

  • Copy the public IP that was displayed in your earlier terraform apply output.
  • Paste it into your browser address bar with http:// in front (e.g. http://44.123.45.67).
  • Confirm that the page no longer loads. The browser should show a connection error.

Now verify from the AWS side.

  • Open the AWS Management Console at https://console.aws.amazon.com.
  • In the search bar at the top, type EC2 and select the EC2 service.
  • Click Instances in the left sidebar.
  • Confirm there are no running instances. You may see the terminated terraform-web-server instance with a "Terminated" state, which is normal.

Why does the terminated instance still appear?

AWS keeps terminated instances visible in the console for about an hour before removing them completely. A "Terminated" status means the instance is already gone and not costing you anything.

Secret mission

Parameterize with Variables

Your Terraform config works, but every value is hardcoded. What if you wanted to deploy to a different region, use a larger instance, or give your resources a custom name? In this mission, you'll introduce Terraform variables to make your configuration reusable across environments.

Clean Up Your Resources

Clean Up Your Resources

You already ran terraform destroy in the previous step, so your AWS cloud resources are gone. Decide whether to keep your local tools and files, pause, or delete everything entirely.

Cost warning

All resources in this project are covered by AWS Free Tier credits for new accounts created after July 15, 2025. The EC2 instance (t3.micro) is included in the free plan for 6 months or until credits are exhausted.

If you re-deploy without destroying afterwards, the instance consumes your free credits while running. Always run terraform destroy when finished.

Resources you used:

  • AWS VPC, subnet, internet gateway, route table, security group, and EC2 instance (already destroyed).
  • AWS IAM user (terraform-user) with access keys.
  • Local project directory learn-terraform-aws on your Desktop.
  • AWS CLI installed via MSI.
  • Terraform binary at C:\terraform.
  • AWS credentials stored at %UserProfile%\.aws.

Keep everything running

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

  • Your local project files, Terraform, and AWS CLI remain installed and ready to use.
  • Your IAM user credentials remain configured. You can reuse them for future Terraform projects.
  • Since you already ran terraform destroy, no cloud resources are running and no credits are being consumed.

Pause - I'll come back to this later

Free up disk space by removing the project files while keeping your tools installed for later.

  • Your AWS infrastructure is already destroyed, so nothing is running in the cloud.
  • Keep Terraform and AWS CLI installed so you can start new projects without reinstalling.
  • Optionally delete the learn-terraform-aws folder if you no longer need the configuration files.

Delete - I don't want to use this again

Remove all project resources, credentials, and tools from your machine. Follow each step below.

  • Delete the local project folder by running this in Command Prompt:
  • Delete the IAM user from the AWS console. Navigate to IAM > Users, select terraform-user, then click Delete.
  • Remove your stored AWS credentials by running:
  • Uninstall the AWS CLI. Open a Command Prompt and run:
  • In the Programs and Features window, select AWS Command Line Interface and click Uninstall.
  • Remove Terraform by deleting its folder and removing it from your PATH. Run:
  • Then remove C:\terraform from your system PATH. Press the Windows key, search for environment variables, select Edit the system environment variables, click Environment Variables, find Path under System variables, select it, click Edit, and remove the C:\terraform entry.
  • Close and reopen any Command Prompt windows to apply the PATH changes.

That's a Wrap!

That's a Wrap!

Nice work! You just deployed a live web server on AWS using nothing but code, then destroyed it all with a single command.

You've learned how to:

  • Write a complete Terraform configuration defining a VPC, subnet, internet gateway, route table, security group, and EC2 instance as Infrastructure as Code.
  • Deploy a live web server accessible from the internet using terraform apply and verify it in your browser.
  • Destroy all infrastructure cleanly with terraform destroy, completing the full IaC lifecycle of write, plan, apply, and destroy.
  • Secret Mission: Parameterize your configuration with Terraform variables to make it reusable across regions and environments.

Ready to quiz yourself?