Deploying WordPress & MySQL infrastructure with NAT Gateway over AWS using Terraform

Samar Pratap Singh
7 min readSep 3, 2020

In this project, we will create a Terraform code which will launch the whole infrastructure of WordPress & MySQL over AWS including VPC, Subnets, Elastic IP for Static IP, NAT Gateway & some more AWS services. This project is much similar to my previous project but here we are going to learn & use Elastic IP & NAT Gateway to provide the internet access to the instance running in the private subnet.

◉ About Project (Steps need to be included)

@ Task 4: Have to launch the whole infrastructure using Terraform

  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. Create a NAT gateway to connect our VPC/Network to the internet world and attach this gateway to our VPC in the public network.
  6. Update the routing table of the private subnet, so that to access the internet it uses the nat gateway created in the public subnet.
  7. 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.
  8. 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:

— A virtual private cloud i.e, VPC is a virtual network dedicated to our AWS account. It is logically isolated from other virtual networks in the AWS Cloud. You can launch your AWS resources, such as Amazon EC2 instances, into your 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:

—A subnet, or subnetwork, is a network inside a network. Subnets make networks more efficient. Through subnetting, network traffic can travel a shorter distance without passing through unnecessary routers to reach its destination.

//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"
}
}

# Lets create Internet Gateway:

— this helps our VPC to have connectivity to the outer 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:

— a routing table in the Internet Gateway helps our instance in a subnet to connect to the outside internet 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 an Elastic IP to get a Static Public IP:

resource "aws_eip" "my_eip" {
vpc = true

depends_on = [
aws_route_table_association.associate_rt_subnet,
]
tags = {
Name = "eip"
}
}

# Creating NAT Gateway:

— Network Address Translation i.e., NAT Gateway is a highly available AWS managed service that makes it easy to connect to the Internet from instances within a private subnet in an AWS Virtual Private Cloud (VPC). Previously, you needed to launch a NAT instance to enable NAT for instances in a private subnet.

resource "aws_nat_gateway" "my_natgateway" {
allocation_id = aws_eip.my_eip.id
subnet_id = aws_subnet.public_subnet.id

depends_on = [
aws_eip.my_eip,
]
tags = {
Name = "nat_gateway"
}
}

# 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_nat_gateway.my_natgateway,
]
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:

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

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

New Key pairs & Security Group were created which helped launch instances…

WordPress & MySQL instances launched in Public & Private Subnets respectively & Elastic IP for Static IP used in NAT Gateway…

◉ Conclusion:

This project was almost similar to my previous project, but here we learned & integrated Elastic IP for NAT Gateway to provide the internet access to the instance running in the private subnet. The complete infrastructure we launched over AWS Cloud with the help of Terraform which was created & destroyed with just one command. With this project, I learned about VPC, Subnet, Elastic IP & NAT Gateway in more depth.

--

--