DEV Community

Cover image for Create Apache Web Server in AWS Using Terraform
Saravanan Gnanaguru
Saravanan Gnanaguru

Posted on • Updated on

Create Apache Web Server in AWS Using Terraform

Table of Contents

Terraform Introduction

  • Terraform is an Infrastructure as Code (IaC) software tool created by HashiCorp.
  • Users define and provide data center infrastructure using a declarative configuration language known as HashiCorp Configuration Language (HCL).
  • Terraform manages external resources (such as public cloud infrastructure, private cloud infrastructure, network appliances, software as a service, and platform as a service) with "providers"
  • HashiCorp maintains an extensive list of official providers, and can also integrate with community-developed providers.
  • Terraform supports a number of cloud infrastructure providers such as Amazon Web Services, Microsoft Azure, IBM Cloud, Google Cloud Platform, DigitalOcean, Oracle Cloud Infrastructure, VMware vSphere, and OpenStack
  • Terraform is one of the extensively used IaC tool in the Cloud DevOps Infra automation space

Install and Configure AWS CLI

  • Install AWS CLI
  • Configure AWS CLI
  • Please note, Configuring AWS using aws configure CLI command, will write the AWS secret and access key to ~/$USER_HOME/.aws/credentials file and it will used to authenticate the terraform infra creation in AWS.

Install and Configure Terraform

Terraform setup in Linux based systems

unzip -d terraform /usr/local/bin/
Enter fullscreen mode Exit fullscreen mode

If terraform executable stored in another path, make sure the path is added in $PATH variable permanently.

AWS Infrastructure Automation

  • We will see How to automate the AWS infrastructure creation using Terraform
  • As part of the demo code, we will create a Apache webserver and run a sample website
  • Architecture of this server follows the single tier method, wherein we will create only a simple Webserver for demo purpose

Basic Terminologies in Terraform

  • Providers
    • It should be cloud provider or on-premise provider on which we will create our infrastructure and resources
  • Resources
    • This indicates the resources like virtual machines, network components, containers we spin-up on the providers
  • Tfstate file
    • This is the state of terraform infrastructure created when we run the commands terraform plan and terraform apply
    • This state file can be stored locally or in a network storage for multi developer environments

Source Code Details

  • Full source code of this tutorial available in GitHub
  • contains the beginning section of terraform code
  • So we have to define terraform with required_providers and we have mentioned aws since we are going to create infra in AWS
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.0"
Enter fullscreen mode Exit fullscreen mode
  • We have already installed and configured aws cli authentication details pointing to the destination AWS account on which the infrastructure will be created
  • The configured credentials stored in the file ~/.aws.credentials
  • We need to provide the reference for the above path in shared_credentials_file value using the creds variable
# Configure the AWS Provider
provider "aws" {
  region = var.region
  shared_credentials_file = var.creds
  profile = "default"
Enter fullscreen mode Exit fullscreen mode
  • Rest of the should have the resource definition required for creating a AWS EC2 instance
  • We need to have below resources for creating an EC2 instance
    1. VPC
    2. Internet Gateway
    3. Subnet
    4. Route table
    5. Security Group and then,
    6. EC2 instance definition
# Create a VPC
resource "aws_vpc" "app_vpc" {
  cidr_block = var.vpc_cidr

  tags = {
    Name = "app-vpc"

resource "aws_internet_gateway" "igw" {
  vpc_id =

  tags = {
    Name = "vpc_igw"

resource "aws_subnet" "public_subnet" {
  vpc_id            =
  cidr_block        = var.public_subnet_cidr
  map_public_ip_on_launch = true
  availability_zone = "us-west-2a"

  tags = {
    Name = "public-subnet"

resource "aws_route_table" "public_rt" {
  vpc_id =

  route {
    cidr_block = ""
    gateway_id =

  tags = {
    Name = "public_rt"

resource "aws_route_table_association" "public_rt_asso" {
  subnet_id      =
  route_table_id =
Enter fullscreen mode Exit fullscreen mode

Cloud Init and User Data

  • Objective of the EC2 instance is to have the Apache Web Server installed on it, when the instance is created
  • So we are providing a shell script in user_data section to install the apache server
  • The script added in user_data section will be invoked via Cloud Init functionality when the AWS server gets created
  • So what ever the commands added in user_data section gets executed whenever the instance getting initialized
  • We can provide any kind scripts in user_data like the example below,
    1. Shell script in Unix based systems
    2. Powershell script in Windows based system
  • Terraform AWS Provider has a syntax to pass the user_data as part of aws_instance resource declaration
resource "aws_instance" "web" {
  ami             = "ami-005e54dee72cc1d00" 
  instance_type   = var.instance_type
  key_name        = var.instance_key
  subnet_id       =
  security_groups = []

  user_data = <<-EOF
  echo "*** Installing apache2"
  sudo apt update -y
  sudo apt install apache2 -y
  echo "*** Completed Installing apache2"

  tags = {
    Name = "web_instance"

  volume_tags = {
    Name = "web_instance"
Enter fullscreen mode Exit fullscreen mode
  • file should have the customised variables, a user wanted to provide before running the infra creation
  • User can also define default value for each variable in the file
variable "region" {
default = "us-west-2"
variable "instance_type" {}
variable "creds" {}
variable "instance_key" {}
variable "vpc_cidr" {}
variable "public_subnet_cidr" {}
Enter fullscreen mode Exit fullscreen mode
  • It is recommended to create separate tf files for separating various resources
  • So we have crreated file for adding resource for AWS VPC security group
resource "aws_security_group" "sg" {
  name        = "allow_ssh_http"
  description = "Allow ssh http inbound traffic"
  vpc_id      =

  ingress {
    description      = "SSH from VPC"
    from_port        = 22
    to_port          = 22
    protocol         = "tcp"
    cidr_blocks      = [""]
    ipv6_cidr_blocks = ["::/0"]

  ingress {
    description      = "HTTP from VPC"
    from_port        = 80
    to_port          = 80
    protocol         = "tcp"
    cidr_blocks      = [""]
    ipv6_cidr_blocks = ["::/0"]

  egress {
    from_port        = 0
    to_port          = 0
    protocol         = "-1"
    cidr_blocks      = [""]
    ipv6_cidr_blocks = ["::/0"]

  tags = {
    Name = "allow_ssh_http"
Enter fullscreen mode Exit fullscreen mode
  • We can define file to see expected output values like ipaddress of instances and hostname etc.


output "web_instance_ip" {
    value = aws_instance.web.public_ip
Enter fullscreen mode Exit fullscreen mode
  • Since we have the custom variables defined in our terraform file, we have provide the values for those custom variables
  • So we have to create a tfvars files and provide the custom variable values
  • User has to provide the EC2 instance pem file key name in instance_key value
  • aws.tfvars
region =  "us-west-2"
instance_type = "t2.micro"
instance_key = "aws_ec2_pem_filename"
creds = "~/.aws/credentials"
vpc_cidr = ""
public_subnet_cidr = ""
Enter fullscreen mode Exit fullscreen mode

Steps to run Terraform

  • Now we will see how to run the above created terraform infrastructure automation
terraform init
terraform plan -var-file=aws.tfvars
terraform apply -var-file=aws.tfvars -auto-approve
Enter fullscreen mode Exit fullscreen mode
  • Once the terrform apply completed successfully it will show the public ipaddress of the apache server as output
aws_instance.web: Creation complete after 33s [id=i-07f19000878a6ec11]

Apply complete! Resources: 7 added, 0 changed, 0 destroyed.


web_instance_ip = ""
Enter fullscreen mode Exit fullscreen mode

Access the Webserver

  • We can access the webserver using the public IP
  • Screenshot Below,

Apache WebServer Page


  • As part of learning we will also cleanup the server using the command,
terraform destroy -var-file=aws.tfvars -auto-approve
Enter fullscreen mode Exit fullscreen mode
  • It shows the destruction completed console log
Changes to Outputs:
  - web_instance_ip = "" -> null
aws_route_table_association.public_rt_asso: Destroying... [id=rtbassoc-085573ee447b7d0d1]
aws_instance.web: Destroying... [id=i-07f19000878a6ec11]
aws_route_table_association.public_rt_asso: Destruction complete after 0s
aws_route_table.public_rt: Destroying... [id=rtb-04025de8f9149983a]
aws_route_table.public_rt: Destruction complete after 0s
aws_internet_gateway.igw: Destroying... [id=igw-06269b7b96264af8f]
aws_instance.web: Still destroying... [id=i-07f19000878a6ec11, 10s elapsed]
aws_internet_gateway.igw: Still destroying... [id=igw-06269b7b96264af8f, 10s elapsed]
aws_internet_gateway.igw: Destruction complete after 19s
aws_instance.web: Still destroying... [id=i-07f19000878a6ec11, 20s elapsed]
aws_instance.web: Still destroying... [id=i-07f19000878a6ec11, 30s elapsed]
aws_instance.web: Destruction complete after 30s
aws_subnet.public_subnet: Destroying... [id=subnet-06304b3b7eb727669] Destroying... [id=sg-098709b525d3553b7] Destruction complete after 0s
aws_subnet.public_subnet: Destruction complete after 0s
aws_vpc.app_vpc: Destroying... [id=vpc-05f7555059de86cf6]
aws_vpc.app_vpc: Destruction complete after 0s

Destroy complete! Resources: 7 destroyed.
Enter fullscreen mode Exit fullscreen mode



Top comments (0)