Automate AWS Infrastructure Using Terraform
This is an hands on project for AWS and Terraform

👑Infrastructure Deployment Steps with Terraform
This blog contains the necessary instructions and Terraform code to deploy an infrastructure stack on a cloud provider using Terraform.
The following steps will guide you through the process of creating a VPC, internet gateway, custom route table, subnet, security group, network interface, elastic IP, and an Ubuntu server with Apache2 installed and enabled.
🧪Prerequisites
Before starting the deployment process, make sure you have the following prerequisites:

Terraform is installed on your local machine. You can download it from the official Terraform website. Download Terraform
An account with the chosen cloud provider (AWS here).
Appropriate access and permissions to create the required resources.
Basic knowledge of Terraform and the cloud provider's infrastructure and networking concepts.
I highly recommend you go through the attached docs as they can be really helpful.
Note: Terraform is declarative that is you describe the desired state of your infrastructure in a Terraform configuration file, specifying the resources, their properties, and the relationships between them. You define the desired end result rather than writing step-by-step instructions or imperative commands to achieve that result
🪜Deployment Steps
Follow the steps below to deploy the infrastructure stack using Terraform:
1. Set Up Terraform and Configure AWS Provider
Make sure to install Terraform on your device then install the Terraform extension from VS Code.

Create a folder and give a name of your choice.
Create
main.tffile. Terraform file is created using.tfextension.Configure AWS provider with Terraform.
To get your AWS Access key and Secret key follow this article -
// Configure the AWS Provider
provider "aws" {
region = "" #Add region
access_key = "" #Add acces_key
secret_key = "" #Add secret_key
}
It is not recommended to hard code the secrets there are other methods to securely store your credentials. But for now, keep it simple!
Docs - Aws Provider
2. Create VPC
- Configure the desired VPC settings, such as CIDR block, name, and other parameters (if you want ).
// 1. Create vpc
resource "aws_vpc" "prod-vpc" {
cidr_block = "10.0.0.0/16"
tags = {
Name = "production"
}
}
While creating a VPC we need to give the resource type and the resource name.
cidr_blockis a required parameter for creating the VPC. This is the CIDR block of VPC.tagsare optional.
Docs - Terraform AWS VPC
3. Create an Internet Gateway
Within the same
main.tffile, configure the internet gateway settings.Associate the internet gateway with the previously created VPC.
// 2. Create Internet Gateway
resource "aws_internet_gateway" "gw" {
vpc_id = aws_vpc.prod-vpc.id
}
Docs - Terraform AWS Internet Gateway
4. Create a Custom Route Table
In the
main.tffile, configure the custom route table settings.Associate the routing table with the VPC.
// 3. Create Custom Route Table
resource "aws_route_table" "prod-route-table" {
vpc_id = aws_vpc.prod-vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id
}
route {
ipv6_cidr_block = "::/0"
gateway_id = aws_internet_gateway.gw.id
}
tags = {
Name = "Prod"
}
}
Here we set our default route to "0.0.0.0/0"
aws_internet_gatewayrefers to the Terraform resource type that represents an internet gateway in AWS..gwis a reference to a specific instance of theaws_internet_gatewayresource. In this case,gwis the name given to theaws_internet_gatewayresource instance that we previously gave in step 2..idrefers to theidattribute of theaws_internet_gatewayresource instance. Theidattribute uniquely identifies the internet gateway resource within AWS.In
ipv6_cidr_block,::/0is the IPv6 equivalent of0.0.0.0/0in IPv4 notation. It denotes that the route matches all IPv6 addresses, effectively making it a default route for IPv6 traffic.
Docs - Terraform AWS Route Tables
🤔 Do you know what is AWS Route Table?
A route table contains a set of rules, called routes, that are used to determine where network traffic from your subnet or gateway is directed.
5. Create a Subnet and associate it with the route table.
- Create Subnet.
// 4. Create a Subnet
resource "aws_subnet" "subnet-1" {
vpc_id = aws_vpc.prod-vpc.id
cidr_block = "10.0.1.0/24"
availability_zone = "us-east-1a"
tags = {
Name = "prod-subent"
}
}
Docs - Terraform AWS Subnet
- Associate the subnet with the Route table.
# 5. Associate subnet with the Route table
resource "aws_route_table_association" "a" {
subnet_id = aws_subnet.subnet-1.id
route_table_id = aws_route_table.prod-route-table.id
}
6. Create a Security Group to Allow Port 22, 80, 443
- Allow inbound traffic on ports 22 (SSH), 80 (HTTP), and 443 (HTTPS).
// 6. Create Security Group to allow port 22,00,443
resource "aws_security_group" "allow_web" {
name = "allow_web_traffic"
description = "Allow web inbound traffic"
vpc_id = aws_vpc.prod-vpc.id
ingress {
description = "HTTPS"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "HTTP"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "SSH"
from_port = 22
to_port = 22
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"]
ipv6_cidr_blocks = ["::/0"]
}
tags = {
Name = "allow_web"
}
}
This declares an
aws_security_groupresource named "allow_web" and specifies a name and description for the security group. It also associates the security group with a VPC identified byaws_vpc.prod-vpc.id.This
ingressblock allows inbound traffic on port 443 (HTTPS) with the "tcp" protocol. Thecidr_blocksparameter allows traffic from any source IP address (0.0.0.0/0), meaning it permits access from any location.Similarly next
ingressblock allows inbound traffic on port 80 (HTTP) with the “tcp” protocol andcidr_blocksparameter allows traffic from (0.0.0.0/0).The
egressblock allows all outbound traffic by specifyingfrom_portandto_portas 0,protocolas "-1" (indicating all protocols), and permitting all destination IP addresses (0.0.0.0/0for IPv4 and::/0for IPv6).
Docs - Terraform AWS Security Group
🤔Do you know what is the difference between ingress and load balancer?
Ingress refers to the process of incoming traffic or data entering a network or a specific network component, such as a server or a service. It generally refers to the path or entry point through which external traffic reaches the internal network.
A load Balancer is a service that acts as a single entry point for incoming traffic and intelligently distributes it across the available resources, such as web servers or application instances, in a way that balances the workload.
7. Create a Network Interface in the Subnet
- Associate the network interface with the previously created subnet that was created in step 4.
// 7. Create a Network Interface in the Subnet
resource "aws_network_interface" "web-server-nic" {
subnet_id = aws_subnet.subnet-1.id
private_ips = ["10.0.1.50"]
security_groups = [aws_security_group.allow_web.id]
}
subnet_idspecifies the ID of the subnet in which the network interface will be created. It references theidattribute of an existingaws_subnetresource namedsubnet-1.private_ipsis an attribute that allows you to assign one or more private IP addresses to the network interface
Docs - Terraform AWS Network Interface
8. Assign an Elastic IP to the Network Interface
- Associate the elastic IP with the network interface that was created in step 7.
// 8. Assign an elastic IP to the network interface.
resource "aws_eip" "one" {
vpc = true
network_interface = aws_network_interface.web-server-nic.id
associate_with_private_ip = "10.0.1.50"
depends_on = [ aws_internet_gateway.gw ]
}
depends_onallows you to create an explicit dependency between two resources.
Docs - Terraform AWS EIP
9. Create Ubuntu Server and Install/Enable Apache2
- Create the Ubuntu server and install Apache2.
// 9. Create Ubuntu server and install/enable apache2
resource "aws_instance" "web-server-instance" {
ami = "ami-053b0d53c279acc90"
instance_type = "t2.micro"
availability_zone = "us-east-1a"
key_name = "main-key"
network_interface {
device_index = 0
network_interface_id = aws_network_interface.web-server-nic.id
}
user_data = <<-EOF
#!/bin/bash
sudo apt update -y
sudo apt install apache2 -y
sudo systemctl start apache2
sudo bash -c 'echo your very first web server > /var/www/html/index.html'
EOF
tags = {
Name = "Web-Server"
}
}
Add your preferred
ami(Amazon Machine Image) and add it'sinstance type,availability zoneandkey_name.If you have trouble generating your key pair refer to these docs -
Docs - AWS Key-Pair
- In
user_dataadd the bash code to install apache2 on the Ubuntu server.
10. Time to run 🏃🏻♂️
Open up the terminal in VS Code or you can also use cmd to make sure that you are in your correct directory.
Here are some basic CLI commands of Terraform: -
Docs - Terraform Basic CLI Commands
- Run
terraform init
You would see something similar to this -

Running the previous command terraform will automatically create the required files.
As you can see in my there are no running instances in AWS EC2 instances.

- Let us now run
terraform apply

- Type
yes

You can also use
terraform apply -auto-approveto auto-approve all the actions.
🎉WOOOOOOHOOOOO!!! Your Ubuntu EC2 instance got successfully launched!!!!

Hurray!!!
You can also verify this by using a Public IPv4 address, it must show a result similar to this.

You can see your very first web server written that is you successfully launched your instance and created a web server.
🏁The End
Congratulations! You have successfully deployed an infrastructure stack using Terraform. The stack includes a VPC, internet gateway, custom route table, subnet, security group, network interface, elastic IP, and an Ubuntu server with Apache2 installed and enabled. You can now access the Ubuntu server over the internet using the elastic IP and start hosting your websites or applications.
Please refer to the Terraform documentation and guides provided by your cloud provider for more detailed information on each step and additional customization options.
So, far you have seen the power of Iac using Terraform. I hope this blog might have helped you get to know about Terraform and a small demonstration of what it can do.
Don't forget to try it by yourself!

➕Full Code
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.0"
}
}
}
# Configure the AWS Provider
provider "aws" {
region = "" //Add region
access_key = "" //Add acces_key
secret_key = "" //Add secret_key
}
# 1. Create vpc
resource "aws_vpc" "prod-vpc" {
cidr_block = "10.0.0.0/16"
tags = {
Name = "production"
}
}
# 2. Create Internet Gateway
resource "aws_internet_gateway" "gw" {
vpc_id = aws_vpc.prod-vpc.id
}
# 3. Create Custom Route Table
resource "aws_route_table" "prod-route-table" {
vpc_id = aws_vpc.prod-vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.gw.id
}
route {
ipv6_cidr_block = "::/0"
gateway_id = aws_internet_gateway.gw.id
}
tags = {
Name = "Prod"
}
}
# 4. Create a Subnet
resource "aws_subnet" "subnet-1" {
vpc_id = aws_vpc.prod-vpc.id
cidr_block = "10.0.1.0/24"
availability_zone = "" //Add Availability Zone
tags = {
Name = "prod-subent"
}
}
# 5. Associate subnet with the Route table
resource "aws_route_table_association" "a" {
subnet_id = aws_subnet.subnet-1.id
route_table_id = aws_route_table.prod-route-table.id
}
# 6. Create Security Group to allow port 22,00,443
resource "aws_security_group" "allow_web" {
name = "allow_web_traffic"
description = "Allow web inbound traffic"
vpc_id = aws_vpc.prod-vpc.id
ingress {
description = "HTTPS"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "HTTP"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "SSH"
from_port = 22
to_port = 22
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"]
ipv6_cidr_blocks = ["::/0"]
}
tags = {
Name = "allow_web"
}
}
# 7. Create a network interface with an ip in the subnet that was created in step 4
resource "aws_network_interface" "web-server-nic" {
subnet_id = aws_subnet.subnet-1.id
private_ips = ["10.0.1.50"]
security_groups = [aws_security_group.allow_web.id]
}
# 8. Assign an elastic IP to the network interface created in step 7
resource "aws_eip" "one" {
vpc = true
network_interface = aws_network_interface.web-server-nic.id
associate_with_private_ip = "10.0.1.50"
depends_on = [ aws_internet_gateway.gw ]
}
# 9. Create Ubuntu server and install/enable apache2
resource "aws_instance" "web-server-instance" {
ami = "" #Add ami
instance_type = "t2.micro"
availability_zone = ""
key_name = "" //enter your key pair that you created
network_interface {
device_index = 0
network_interface_id = aws_network_interface.web-server-nic.id
}
user_data = <<-EOF
#!/bin/bash
sudo apt update -y
sudo apt install apache2 -y
sudo systemctl start apache2
sudo bash -c 'echo your very first web server > /var/www/html/index.html'
EOF
tags = {
Name = "Web-Server"
}
}
📄 Git Repo -
Star and fork the repository.
Clone the repository.
Read the steps from STEPS.md
Automate your AWS infrastructure.





