Infrastructure as Code (IaC): Deploy a LAMP Stack Application on AWS with Terraform

Lateef Taiwo
12 min readSep 4, 2023

--

Architecture Diagram adapted from AWS Workshop Page

In this article, I will host and deploy a LAMP (Linux, Apache, MySQL and PHP) stack application on AWS using a popular Infrastructure as code tool called Terraform. The LAMP stack application will be hosted in EC2 instances in different public subnets, located in different Availability Zones (AZs) within an Auto-Scaling Group (ASG), all residing in a vpc. Before we dive into the nitty gritty of this article, lets define some terms and services used.

  1. LAMP stack: The LAMP stack is a popular and widely used software stack for building and deploying web applications. The LAMP stack has been popular for many years due to its ease of use, cost-effectiveness, and the fact that all the components are open-source. It is commonly used for hosting websites and web applications and has been instrumental in the growth of the internet and web development. It’s an acronym that stands for:
    - Linux: The operating system (OS) that serves as the foundation of the stack. Linux is an open-source, Unix-like OS that provides the necessary environment for running web servers and other components.
    - Apache: The web server software that handles HTTP requests and serves web pages to users. Apache is one of the most widely used web servers in the world and is known for its stability and reliability.
    - MySQL: The relational database management system (RDBMS) used to store and manage data. MySQL is open-source and widely used for web applications that require a structured data storage system.
    - PHP: The server-side programming language used for dynamic web content. PHP (Hypertext Preprocessor) is embedded within HTML and allows developers to create dynamic and interactive web pages.
  2. Terraform: Terraform is an open-source infrastructure as code (IaC) tool developed by HashiCorp. It allows you to define, create, manage, and update your cloud resources and infrastructure in a declarative way. With Terraform, you can define your infrastructure using a domain-specific language called HashiCorp Configuration Language (HCL) or Configuration Language (CL), and then use Terraform commands to apply those definitions to create and manage resources.
  3. VPC (Virtual Private Cloud): A VPC allows you to create a virtualized network within a cloud provider’s infrastructure, isolating your resources and providing control over network configuration and security.
  4. EC2 (Elastic Compute Cloud): Amazon Elastic Compute Cloud (Amazon EC2) provides on-demand, scalable computing capacity in the Amazon Web Services (AWS) Cloud. Using Amazon EC2 reduces hardware costs so you can develop and deploy applications faster. You can use Amazon EC2 to launch as many or as few virtual servers as you need, configure security and networking, and manage storage.
  5. Auto Scaling Group (ASG): An Auto Scaling Group contains a collection of EC2 instances that are treated as a logical grouping for the purposes of automatic scaling and management. So you can either scale your applications horizontally or vertically.
  6. Public Subnets: A public subnet is a subnet linked to a route table containing a route to an Internet gateway, enabling connectivity between the Virtual Private Cloud (VPC) and both the Internet and various AWS services.
  7. Availability Zones: Availability Zones (AZs) are isolated data centers located within specific regions in which public cloud services originate and operate. In AWS, an Availabilty zone is typically comprised of two or three data centers.

Install Required Software and Tools

  1. Install Terraform: To use Terraform, you will first need to install it. HashiCorp distributes Terraform as a binary package. To install terraform, click on this offical installation guide and follow the installation steps for your operating system. In this article, I will install terraform on a debian based (ubuntu, debian, kali et cetera) Linux operating system through the following steps:
  • Step 1: Ensure that your system is up to date and you have installed the gnupg, software-properties-common, and curl packages installed.
sudo apt-get update && sudo apt-get install -y gnupg software-properties-common
  • Step 2: Install the HashiCorp GPG key
wget -O- https://apt.releases.hashicorp.com/gpg | \
gpg --dearmor | \
sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg
  • Step 3: Verify the key’s fingerprint.
gpg --no-default-keyring \
--keyring /usr/share/keyrings/hashicorp-archive-keyring.gpg \
--fingerprint

The gpg command will report the key fingerprint as shown in the image above.

  • Step 4: Add the official HashiCorp repository to your system. The lsb_release -cs command finds the distribution release codename for your current system, such as buster, groovy, or sid.
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \
https://apt.releases.hashicorp.com $(lsb_release -cs) main" | \
sudo tee /etc/apt/sources.list.d/hashicorp.list
  • Step 5: Update repositories to download the package information from HashiCorp.
sudo apt update
  • Step 6: Install Terraform from the new repository.
sudo apt-get install terraform

Step 7: Verify the installation

terraform --version

OR

terraform -help

Install AWS CLI

aws --version

Configure AWS cli to use Terraform to make api calls to AWS cloud

To configure aws cli, create an IAM (Identity and Access Management) user, then download the csv file containing the IAM user’s access key id and secret access key.

Create an IAM user

  • Sign into the aws console and search for IAM. On the IAM dashboard, under Access Management click on users then click on create user.
  • Type a preferable username and click next
  • Create a group, type a group name and attach AdministratorAccess policy to it and click create user group.
  • Check the box beside the group created and click next.
  • You can add a tag if you wish to but it is optional. type a preferred key and value for the tag. Click create user.
  • Next, Click on the IAM username and click on create access key
  • Choose “Command Line Interface (CLI)”
  • Scroll down, check the box under confirmation and click “Next”
  • Type an optional description tag value, click create access key

You will see a message saying “Access key created”. Download the csv file. This file contains your access key id and secret access key id.

Configure AWS cli to use terraform to make api calls to AWS cloud

  • On your terminal or command prompt, type aws configure
  • Open the csv file downloaded either on your terminal or cli or using Microsoft excel. Copy the access key id, paste it in the terminal prompt for AWS Access Key ID and press enter.
  • Copy the secret access key and paste it on the terminal prompt for AWS Secret Access Key, enter a default region and leave the default json format. With these, the aws cli is now configured with the created IAM user access keys.

The next steps involves writing the terraform code that will deploy ec2 instances in autoscaling groups inside two public subnets in 3 Availability zones.

  • Create a new project directory.
  • Open the directory in your terminal (Linux and MacOS)or gitbash (windows). Open the project directory using Visual Studio code from the terminal or gitbash by typing “code .”
  • Create a new file and name it main.tf, then paste the Hashicorp configuration language (HCL) code in it. For this article, I will write the entire terraform code in main.tf file. In subsequent articles, terraform modules will be used to provide predefined resource structures. Endeavour to read through the code especially the comments section to gain more insights about what this terraform code will do.
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 3.5.0"
}
}
}

# Configure the AWS Provider
provider "aws" {
region = "eu-west-2"
}

# Create a Key pair

resource "aws_key_pair" "abdul-aws-key-pair" {
key_name = "abdul-aws-key-pair"
public_key = tls_private_key.rsa.public_key_openssh
}

# RSA key of size 4096 bits
resource "tls_private_key" "rsa" {
algorithm = "RSA"
rsa_bits = 4096
}

# Create a local file to store the key pair which will be used to access the instances cia ssh
resource "local_file" "abdul-aws-key-pair" {
content = tls_private_key.rsa.private_key_pem
filename = "abdul-aws-key-pair"
}

# Get latest Amazon Linux 2 AMI
data "aws_ami" "amazon-linux-2" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["amzn2-ami-hvm*"]
}
}


# Define the security group for the EC2 Instance
resource "aws_security_group" "aws-sg-webserver" {
name = "aws-sg-webserver"
description = "Allow incoming connections"
vpc_id = aws_default_vpc.default.id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "Allow incoming HTTP connections"
}
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "Allow incoming SSH connections (Linux)"
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "Webserver-sg"
}
}
resource "aws_default_vpc" "default" {

}


resource "aws_instance" "vm-server" {
ami = data.aws_ami.amazon-linux-2.id
instance_type = "t2.micro"
vpc_security_group_ids = [aws_security_group.aws-sg-webserver.id]
key_name = aws_key_pair.abdul-aws-key-pair.key_name
user_data = file("userdata.tpl")

tags = {
Name = "aws-webserver-demo"
}
}


resource "aws_launch_template" "aws-launch-template" {
name = "aws-launch-template"
image_id = data.aws_ami.amazon-linux-2.id
instance_type = "t2.micro"
key_name = aws_key_pair.abdul-aws-key-pair.key_name
vpc_security_group_ids = [aws_security_group.aws-sg-webserver.id]
tag_specifications {
resource_type = "instance"
tags = {
Name = "aws-webserver-demo"
}
}
user_data = filebase64("userdata.tpl")
}

# Use an autoscaling group of 2 minimum EC2 instances in 3 availability zones
resource "aws_autoscaling_group" "aws-autoscaling-group" {
availability_zones = ["eu-west-2a", "eu-west-2b", "eu-west-2c"]
desired_capacity = 2
max_size = 3
min_size = 2

launch_template {
id = aws_launch_template.aws-launch-template.id
version = "$Latest"
}
}
  • Notice that there is a template file named “userdata.tpl” in the terraform code above. This file will be used to install packages on the EC2 instances.
  • Now, create a new file in the project directory and name is userdata.tpl. Then paste the following code.
#!/bin/sh

# Install a LAMP stack
amazon-linux-extras install -y lamp-mariadb10.2-php7.2 php7.2
yum -y install httpd php-mbstring

# Start the web server
chkconfig httpd on
systemctl start httpd

# Install the web pages for our lab
if [ ! -f /var/www/html/immersion-day-app-php7.tar.gz ]; then
cd /var/www/html
wget https://aws-joozero.s3.ap-northeast-2.amazonaws.com/immersion-day-app-php7.tar.gz
tar xvfz immersion-day-app-php7.tar.gz
fi

# Install the AWS SDK for PHP
if [ ! -f /var/www/html/aws.zip ]; then
cd /var/www/html
mkdir vendor
cd vendor
wget https://docs.aws.amazon.com/aws-sdk-php/v3/download/aws.zip
unzip aws.zip
fi

# Update existing packages
yum -y update
  • Now, its time to start get our hands dirty with terraform commands. Prior to that, first familiarize yourself with the following terraform commands.
  • terraform init: This command is used to initialize the terraform.
  • terraform validate: This command is used to validate the terraform code.
  • terraform plan: This command is used to describe the plan. This is highly recommended to run before apply the changes.
  • terraform show: Show the current state or a saved plan
  • terraform apply: If you are satisfied with changes, run this command to apply the changes
  • terraform destroy: Deletes and removes the provisioned infrastructure resources
  • Now, type terraform init
  • Next, type terraform plan
  • Type terraform validate to validate the configuration. If everything works well, You will see a message “Success! The configuration is valid”
  • Now its time to apply our configuration. Type terraform apply, enter yes to accept the configuration
  • This deploys our infrastructure, creates a key pair, creates the default vpc, security group and every other thing specified in the main.tf file. You will notice that the keypair was created in the project directory. This will be used for ssh access into our EC2 instances.
  • Login to the AWS console using the IAM credentials created. Search for EC2 and ensure you select london region because our servers are in the london region. You will the EC2 instances
  • Click on any of the instances and copy the public Ip address to access the web application.
  • Copy and paste the Public Ip addresses of the other instances on your web browser and you will see the same web application. Voila!! You have automated the deployments of a LAMP stack application using terraform.
  • If you want to check other services used in this project on the aws console, navigate to the EC2 dashboard and scroll down to auto scaling groups.
  • You will see an auto-scaling group. Click on the auto-scaling group name to view its details and other information about it.
  • If you click on keypairs, You will see the created keypair.
  • To see the VPC and subnets, search for VPC and on the left hand side click your VPC, click subnets, you will see three subnets and three availability zones (“eu-west-2a”, “eu-west-2b”, “eu-west-2c”) as specified in the main.tf file

Clean-Up

One beautiful thing about terraform is that you can delete (destroy) all the provisioned infrastructure (resources) with just one command, terraform destroy.

Now, run terraform destroy command to delete all the resources to avoid unnecessary costs.

You will be prompted to type yes to confirm. Type yes and watch terraform destroy the infrastructure ensuring a proper clean up of all provisioned resources.

Thank you for reading this article till the end. You have learnt how to use one of the most powerful Infrastructure as code tool to provision web servers and deploy an application on the servers. Follow me for more interesting articles on Cloud and DevOps.

References

AWS EC2 documentation: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/concepts.html
AWS ASG documentation: https://docs.aws.amazon.com/autoscaling/ec2/userguide/auto-scaling-groups.html
Hashicorp Terraform: https://www.terraform.io/
Terraform Installation: https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli
Subnets: https://docs.aws.amazon.com/vpc/latest/userguide/modify-subnets.html
AWS AZ documentation: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html#concepts-availability-zones

--

--

Lateef Taiwo

A Cloud engineer, lover of everything Linux/Unix, DevOps Practitioner