Deploying WordPress & MySQL instances in two Subnets in a VPC on AWS using Terraform

In this project, we will create a Terraform code which will automatically go to AWS and configure various services & create the whole infrastructure for us. We will create a web portal for our company with all the security as much as possible. So, we use the WordPress software with a dedicated database server.
The database will not be accessible from the outside world for security purposes. We will make the WordPress site available to the client but not the DataBase through the Subnets in our own created VPC.

◉ About Project (Steps need to be included)

1) Write an Infrastructure as code using Terraform, which automatically create a VPC.

2) In that VPC we have to create 2 subnets:
a) public subnet [ Accessible for Public World! ]
b) private subnet [ Restricted for Public World! ]

3) Create a public-facing internet gateway for connecting our VPC/Network to the internet world and attach this gateway to our VPC.

4) Create a routing table for Internet gateway so that instance can connect to the outside world, update and associate it with the public subnet.

5) Launch an ec2 instance which has WordPress setup already having the security group allowing port 80 so that our client can connect to our WordPress site. Also, attach the key to the instance for further login into it.

6) Launch an ec2 instance which has MYSQL setup already with security group allowing port 3306 in a private subnet so that our WordPress VM can connect with the same. Also, attach the key with the same.

Note: WordPress instance needs to be part of public subnet so that our client can connect our site & MySQL instance needed to be part of private subnet so that outside world can’t connect to it for security.

◉ I have Performed the Task and attached the screenshots for your reference:

Step 1: First let's write the Terraform code which will automatically launch the whole infrastructure.

# Set provider for Cloud services, here it is AWS:

provider "aws" {
region = "ap-south-1"
profile = "samar"
}

# For creating a VPC:

resource "aws_vpc" "myvpc" {
cidr_block = "192.168.0.0/16"
instance_tenancy = "default"
enable_dns_hostnames = true
tags = {
Name = "my_vpc"
}
}

# Creating two subnets in above VPC. One is subnet is Public and the other is Private.

//Public subnet for WordPress instance
resource "aws_subnet" "public_subnet" {
vpc_id = aws_vpc.myvpc.id
cidr_block = "192.168.1.0/24"
availability_zone = "ap-south-1a"
map_public_ip_on_launch = true
depends_on = [
aws_vpc.myvpc,
]
tags = {
Name = "subnet_for_wp"
}
}
//Public subnet for MySQL instance
resource "aws_subnet" "private_subnet" {
vpc_id = aws_vpc.myvpc.id
cidr_block = "192.168.2.0/24"
availability_zone = "ap-south-1b"
depends_on = [
aws_vpc.myvpc,
]
tags = {
Name = "subnet_for_mysql"
}
}

# Create Internet Gateway which helps VPC to have connectivity to the internet world

resource "aws_internet_gateway" "mygateway" {
vpc_id = aws_vpc.myvpc.id
tags = {
Name = "vpc_internet_gateway"
}
}

# Create a routing table for Internet gateway so that instance can connect to the outside world.

resource "aws_route_table" "myroute" {
vpc_id = aws_vpc.myvpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.mygateway.id
}
depends_on = [
aws_internet_gateway.mygateway,
]
tags = {
Name = "routing_table"
}
}

# Associating the above routing table to the Public Subnet, so that instance in that subnet can connect to the internet.

resource "aws_route_table_association" "associate_rt_subnet" {
depends_on = [
aws_route_table.myroute,
]
subnet_id = aws_subnet.public_subnet.id
route_table_id = aws_route_table.myroute.id
}

# Creating key pair (in “pem” format) to access the instance using SSH protocol if required.

resource "tls_private_key" "mykey1" {
algorithm = "RSA"
}
resource "aws_key_pair" "key_access" {
key_name = "mykey"
public_key = tls_private_key.mykey1.public_key_openssh
depends_on = [
tls_private_key.mykey1,
aws_route_table_association.associate_rt_subnet,
]
tags = {
Name = "access key"
}
}

# Create Security Group for WordPress instance allowing port no. 80

resource "aws_security_group" "sg_wordpress" {
depends_on = [
aws_vpc.myvpc,
aws_subnet.public_subnet,
]
name = "wp_sg"
vpc_id = aws_vpc.myvpc.id
description = "SSH & HTTP inbound traffic are allowed"
ingress {
description = "Allow SSH"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}

ingress {
description = "Allow HTTP"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "sg_wordpress"
}
}

# Now let’s create WordPress instance in the Public Subnet

resource "aws_instance" "wp_instance" {
ami = "ami-000cbce3e1b899ebd"
instance_type = "t2.micro"
subnet_id = aws_subnet.public_subnet.id
key_name = aws_key_pair.key_access.key_name
security_groups = [aws_security_group.sg_wordpress.id]
depends_on = [
aws_security_group.sg_wordpress,
tls_private_key.mykey1,
]
tags = {
Name = "wp_instance"
}
}

# Create Security Group for MySQL instance allowing port no. 3306

resource "aws_security_group" "sg_mysql" {
depends_on = [
aws_vpc.myvpc,
aws_subnet.private_subnet,
]
name = "mysql_sg"
vpc_id = aws_vpc.myvpc.id
description = "MySQL inbound traffic is allowed"

ingress {
description = "Allow MySQL"
from_port = 3306
to_port = 3306
protocol = "tcp"
security_groups = [aws_security_group.sg_wordpress.id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "sg_mysql"
}
}

# Now create MySQL instance in the Private Subnet

resource "aws_instance" "mysql_instance" {
depends_on = [
aws_security_group.sg_mysql,
aws_instance.wp_instance,
]
ami = "ami-08706cb5f68222d09"
instance_type = "t2.micro"
subnet_id = aws_subnet.private_subnet.id
key_name = aws_key_pair.key_access.key_name
security_groups = [aws_security_group.sg_mysql.id]
tags = {
Name = "mysql-instance"
}
}

# Launch the WordPress in browser:

— this resource will automatically retrieve the Public IP of WordPress instance & then launches in the chrome browser for us without our involvement.

resource "null_resource" "nulllocal2"  {
depends_on = [
aws_instance.mysql_instance,
]
provisioner "local-exec" {
command = "start chrome ${aws_instance.wp_instance.public_ip}"
}
}

Step2: We will use the Terraform code that we created above to launch the whole infrastructure & then it will automatically launch the website for us.

# Initiate the terraform code:

— this command will initialize the terraform code & download the required plugins from the internet.

terraform init

# Validate the terraform code:

terraform validate

# Execute or apply the terraform code:

terraform apply -auto-approve

The whole infrastructure launched successfully:

# The WordPress launched:

— terraform code automatically launched the WordPress site in Chrome browser for us, without any involvement from our side. We created a project based on End-to-end Automation.

# Lets see services which automatically got configured for us just by using one terraform code:

New Key pairs ,Security Group were created and used to launch WordPress & MySQL instances…

Launched one VPC & inside it two Subnets out of which one was Public & other Private

Internet Gateway & Routing Table were created to help WordPress instance inside the Public Subnet can connect to the internet.

# Destroy the infrastructure:

— as this was just a practical which we completed successfully & now we dont need this infrastructure. Hence, we will destroy the whole infrastructure to prevent unnecessary billing, with just one command:

terraform destroy -auto-approve

◉ Conclusion: