Skip to main content

Command Palette

Search for a command to run...

Simple EC2 Web Server using Terraform

Updated
3 min read
Simple EC2 Web Server using Terraform

In this project, we are going to setup the following using Terraform,

  • VPC

  • Public subnet

  • Internet gateway

  • Route table

  • Security group

  • EC2 instance

  • Elastic IP

The complete terraform code for this project is available on github

The project folder contains 4 files as represented in the below structure.

simple-ec2-web-server/
├── main.tf
├── providers.tf
├── datasources.tf
└── user-data.tpl

Step 1 : providers .tf

The providers .tf file allows Terraform to connect and interact with AWS Cloud.

terraform {
  required_providers {
    aws = {
      source = "hashicorp/aws"
    }
  }
}

provider "aws" {
  region                   = "us-east-1"
  shared_credentials_files = ["~/.aws/credentials"]
  profile                  = "vscode"
}

Step 2 : datasources .tf

This file is used to provide the latest ec2 instance ami id to the main .tf file.

data "aws_ami" "instance_ami" {
  most_recent = true
  owners      = ["137112412989"]
  filter {
    name   = "name"
    values = ["al2023-ami-2023.5.20240722.0-kernel-6.1-x86_64"]
  }
}

Step 3 : user-data .tpl

We need to provide user data for the ec2, so that it can download and setup server and display the instance's private ip in the webpage.

#!/bin/bash
# Use this for your user data (script from top to bottom)
# install httpd (Linux 2 version)
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
echo "<h1>Hello World from $(hostname -f)</h1>" > /var/www/html/index.html

Step 4 : main .tf

First we need to create a VPC.

resource "aws_vpc" "demo_vpc" {
  cidr_block = "10.0.0.0/16"

  tags = {
    name = "demo-vpc"
  }
}

Then create a public subnet inside the VPC

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

  tags = {
    name = "public-subnet-1"
  }
}

Attach an internet gateway to the vpc

resource "aws_internet_gateway" "demo_internet_gateway" {
  vpc_id = aws_vpc.demo_vpc.id

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

Create a public route table for the vpc

resource "aws_route_table" "demo_public_rt" {
  vpc_id = aws_vpc.demo_vpc.id

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

Add a route in the route table which directs 0.0.0.0/0 traffic to internet gateway

resource "aws_route" "default_route" {
  route_table_id         = aws_route_table.demo_public_rt.id
  destination_cidr_block = "0.0.0.0/0"
  gateway_id             = aws_internet_gateway.demo_internet_gateway.id
}

Associate the route table to the subnet

resource "aws_route_table_association" "demo_public_assoc" {
  subnet_id      = aws_subnet.pub_sub_1.id
  route_table_id = aws_route_table.demo_public_rt.id
}

Create a security group for the vpc. It should allow inbound HTTP traffic on port 80 and all traffic for outbound.

resource "aws_security_group" "demo_sg" {
  name        = "dev-sg"
  description = "dev security group"
  vpc_id      = aws_vpc.demo_vpc.id

# Allow only port 80 inbound
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

# Allow all traffic for outbound
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

Create an ec2 instance with user data

resource "aws_instance" "demo" {
  instance_type          = "t2.micro"
  ami                    = data.aws_ami.instance_ami.id
  user_data              = file("user-data.tpl")
  vpc_security_group_ids = [aws_security_group.demo_sg.id]
  subnet_id              = aws_subnet.pub_sub_1.id
}

Output the public ip of instance in the terminal

output "ec2_public_ip" {
  description = "The public IP of the EC2 instance"
  value       = aws_instance.demo.public_ip
}

Create and define the elastic ip is for use in vpc

resource "aws_eip" "elastic_ip"{
    instance = aws_instance.demo.id
    domain = "vpc"
}

Associate the elastic ip with the ec2 instance

resource "aws_eip_association" "eip_assoc"{
    instance_id = aws_instance.demo.id
    allocation_id = aws_eip.elastic_ip.id
}

Output the elastic ip in the terminal (Just for you to know the elastic IP)

output "ec2_eip" {
  description = "The Elastic IP of the EC2 instance"
  value       = aws_eip.elastic_ip.public_ip
}

Step 5 : Result

Now when you access the public IP of the instance OR the elastic IP (both should be the same) from your browser, you'll see similar webpage. (Please note to access the ip in http:// and not https://)