Today we're going to learn how to create an AWS web server using a tool called OpenTofu.
What is OpenTofu?
OpenTofu is an open-source infrastructure as code tool that allows users to define and manage cloud and on-premises resources using human-readable configuration files.
Step 0: Prerequisites
Before we start, there are a few things we need to do:
Install OpenTofu
Go to OpenTofu installation page and choose a method of installation for your operating system. For example, on macOS, you can use Homebrew:
brew install opentofu
Create an AWS Account
Go to AWS sign-up page and follow the steps to create a new account.
Generate an SSH Key Pair
Run the following command to generate a new SSH key pair (replace ~/.ssh/id_ed25519
with your desired path if needed):
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519
Step 1: Setting Up the Playground
First we will need to let OpenTofu know which cloud provider we require, for this guide it will be AWS.
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
}
}
}
Run the following command to tell OpenTofu to download the AWS provider binary.
tofu init
After running the command we need to tell OpenTofu where our playground (called a "region") is located.
We will also need to add our AWS access & secret key so that we can create and remove resources.
provider "aws" {
region = "ap-southeast-1"
access_key = "AKxxx"
secret_key = "SECRET_KEY"
}
This tells OpenTofu to set up our playground in a place called "ap-southeast-1".
Note that the docs mention multiple ways to authenticate ourselves but we will hard code the credentials in the configuration this time.
Step 2: Creating a Big Sandbox (VPC)
Next, we will create a big sandbox where we can play. This sandbox is called a Virtual Private Cloud or VPC.
resource "aws_vpc" "vpc" {
cidr_block = "10.0.0.0/16"
tags = {
Name = "vpc"
}
}
This creates a VPC with the name vpc
. A VPC is like our very own playground with boundaries.
Step 3: Making Small Sand Pits (Subnets)
Inside our big sandbox, we will make two smaller sand pits called subnets. One will be for public use, and the other for private use.
resource "aws_subnet" "public" {
vpc_id = aws_vpc.vpc.id
cidr_block = "10.0.0.0/24"
tags = {
Name = "public subnet"
}
}
resource "aws_subnet" "private" {
vpc_id = aws_vpc.vpc.id
cidr_block = "10.0.1.0/24"
tags = {
Name = "private subnet"
}
}
Now we have two subnets in our VPC.
Step 4: Adding a Gate (Internet Gateway)
To let the outside world come into our playground, we will create a gate called the Internet Gateway.
resource "aws_internet_gateway" "igw" {
vpc_id = aws_vpc.vpc.id
tags = {
Name = "igw"
}
}
This internet gateway allows our playground to connect to the internet.
Step 5: Getting a Special Key (Elastic IP)
we will get a special key called Elastic IP (which is a fancy word for a public IP address) to use with our Internet Gateway.
resource "aws_eip" "eip" {
domain = "vpc"
depends_on = [aws_internet_gateway.igw]
}
This Elastic IP will help us connect to the internet.
Step 6: Setting Up a NAT Gateway
We create something called a NAT Gateway in our public subnet. This helps our private subnet talk to the internet without showing its identity.
resource "aws_nat_gateway" "nat_gw" {
subnet_id = aws_subnet.public.id
allocation_id = aws_eip.eip.id
depends_on = [aws_internet_gateway.igw]
tags = {
Name = "nat"
}
}
This NAT Gateway helps our private subnet communicate with the outside world.
Step 7: Creating Routes (Route Tables)
we will create maps (route tables) for our public and private subnets.
resource "aws_route_table" "public" {
vpc_id = aws_vpc.vpc.id
tags = {
Name = "route-table-public"
}
}
resource "aws_route" "public" {
destination_cidr_block = "0.0.0.0/0"
route_table_id = aws_route_table.public.id
gateway_id = aws_internet_gateway.igw.id
}
resource "aws_route_table_association" "public" {
route_table_id = aws_route_table.public.id
subnet_id = aws_subnet.public.id
}
resource "aws_route_table" "private" {
vpc_id = aws_vpc.vpc.id
tags = {
Name = "route-table-private"
}
}
resource "aws_route" "private" {
destination_cidr_block = "0.0.0.0/0"
route_table_id = aws_route_table.private.id
nat_gateway_id = aws_nat_gateway.nat_gw.id
}
resource "aws_route_table_association" "private" {
route_table_id = aws_route_table.private.id
subnet_id = aws_subnet.private.id
}
These maps show our subnets how to reach different places.
Step 8: Making Rules for Entry (Security Group)
we will create rules that say who can come into our playground. These rules are called a Security Group.
resource "aws_security_group" "sg_web" {
name = "web_security"
description = "Allow HTTP, HTTPS & SSH"
vpc_id = aws_vpc.vpc.id
tags = {
Name = "web-security"
}
}
resource "aws_vpc_security_group_ingress_rule" "allow_http" {
security_group_id = aws_security_group.sg_web.id
cidr_ipv4 = "0.0.0.0/0"
ip_protocol = "tcp"
from_port = 80
to_port = 80
}
resource "aws_vpc_security_group_ingress_rule" "allow_https" {
security_group_id = aws_security_group.sg_web.id
cidr_ipv4 = "0.0.0.0/0"
ip_protocol = "tcp"
from_port = 443
to_port = 443
}
resource "aws_vpc_security_group_ingress_rule" "allow_ssh" {
security_group_id = aws_security_group.sg_web.id
cidr_ipv4 = "0.0.0.0/0"
ip_protocol = "tcp"
from_port = 22
to_port = 22
}
resource "aws_vpc_security_group_egress_rule" "allow_all_traffic_ipv4" {
security_group_id = aws_security_group.sg_web.id
cidr_ipv4 = "0.0.0.0/0"
ip_protocol = "-1"
}
This security group allows anyone to visit our web server and let us manage it from anywhere.
Step 9: Adding SSH Key Pair to AWS
Using the previously created SSH key pair, we will upload the public key to AWS. This will let us access our web server.
resource "aws_key_pair" "key_pair" {
key_name = "my OpenTofu key"
public_key = file("~/.ssh/id_ed25519.pub")
}
Step 10: Create the Web Server (EC2 Instance)
Finally, we will create our web server, which is an EC2 instance.
Additionally we will use 30GB of EBS storage and run some commands to install a web server.
resource "aws_instance" "webserver" {
ami = "ami-0acbb557db23991cc"
instance_type = "t2.micro"
subnet_id = aws_subnet.public.id
associate_public_ip_address = true
key_name = aws_key_pair.key_pair.key_name
vpc_security_group_ids = [aws_security_group.sg_web.id]
depends_on = [aws_internet_gateway.igw]
tags = {
Name = "webserver"
}
root_block_device {
volume_size = 30
volume_type = "gp3"
delete_on_termination = true
}
user_data = <<-EOF
#!/bin/bash
sudo apt-get update
sudo apt-get install -y lighttpd
#echo "hi world" > /var/www/html/index.html
EOF
}
This EC2 instance will have:
- An AMI (Debian template) for creating the instance.
- A type
t2.micro
(small but sufficient for learning). - A public subnet to connect to the internet.
- A security group to allow access to HTTP,HTTPS & SSH.
- A SSH key pair for secure access.
- 30GB EBS storage space.
- A script that installs Lighttpd when the instance starts.
Apply configuration to AWS
To apply the configuration to AWS, run the following commands.
tofu validate
tofu apply
tofu validate
validates the syntax
tofu apply
will apply the config to AWS
Display public IP address
Adding the following block will display our web server public IP address after the configuration has been applied
output "webserver_ip" {
value = aws_instance.webserver.public_ip
}
Conclusion
Congratulations! You've just set up a web server using OpenTofu.
With these steps, you now have a functional playground (VPC) with a sand pit (subnet), a gate (internet gateway), maps (route tables), rules (security group), a special key (SSH key pair), and your very own web server (EC2 instance) ready to greet the world.
Top comments (0)