# 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](https://github.com/hishcodes/Simple-ec2-web-server)

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

```plaintext
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.

```json
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.

```json
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.

```plaintext
#!/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.

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

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

Then create a public subnet inside the VPC

```json
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

```json
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

```json
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

```json
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

```json
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.

```json
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

```json
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

```json
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

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

Associate the elastic ip with the ec2 instance

```json
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)

```json
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://)

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1722960915678/0c6d8bfd-87b0-45ea-9ecd-dd09107a4cfa.png align="center")
