CMS Infrastructure as code (IAC) deployment on AWS using terraform

Shivangi Sharma
5 min readSep 16, 2020

A Content Management System is a software platform that lets its users create, edit, archive, collaborate, report, publish, distribute, and inform. Its Graphic User Interface (GUI) makes interacting with a website’s database user friendly. Examples of the most widely used open-source CMS platforms include- WordPress, Joomla, Drupal, Magento (e-commerce).

Creating an entire infrastructure of any CMS like WordPress can be a tedious task, but that can be solved by using terraform!!

Terraform is a provisioning tool, which means they are designed to provision the servers themselves (as well as the rest of your infrastructure, like load balancers, databases, networking configuration, etc) hence we can use it to deploy WordPress and MySQL on AWS.

So let's start the creation of WordPress and MySQL on AWS using infrastructure as code by terraform!!

We would be creating a web portal for our company with as much security as possible, here we are using a CMS like WordPress with a dedicated database server like MySQL.

The database should not be accessible by the general public for security purposes. We only need to make the web portal public to clients, therefore we would be creating separate private and public subnets. We would also be using elastic IP and creating a custom NAT gateway to provide internet access to the instances running in the private subnet.

Follow the below-given steps for better understanding-

Provider

Mention the provider and region that would be used for deployment. We would be using AWS, but other providers like GCP and Azure can also be used for the same.

provider "aws" {region  = "ap-south-1"profile = "<profile name>"}

VPC

Create a main VPC and 2 different subnets

resource "aws_vpc" "my_vpc" {cidr_block = "10.1.0.0/16"enable_dns_support= trueenable_dns_hostnames= truetags = {Name = "main-vpc"}}

Private Subnet

Private Subnet is restricted to the public and will be used for securing the MySql database.

resource "aws_subnet" "private-subnet" {vpc_id     = "${aws_vpc.my_vpc.id}"cidr_block = "10.1.1.0/24"map_public_ip_on_launch= trueavailability_zone = "ap-south-1a"tags = {Name = "private-subnet"}}

Public Subnet

Public Subnet is accessible to the public and will be used for WordPress.

resource “aws_subnet” “public-subnet” {
vpc_id = “${aws_vpc.my_vpc.id}”
cidr_block = “10.1.0.0/24”map_public_ip_on_launch= trueavailability_zone = “ap-south-1a”tags = {Name = “public-subnet” }}

Internet Gateway

Create a public-facing internet gateway to connect our VPC/network to the internet and attach this gateway to the VPC.

resource "aws_internet_gateway" "gw" {vpc_id = "${aws_vpc.my_vpc.id}"tags = {Name = "NATgateway" }}

NAT Gateway and Elastic IP

Create an elastic IP and NAT Gateway to connect VPC/network to the internet and attach this gateway to the VPC in the public network.

resource "aws_eip" "eip" {vpc =true}resource "aws_nat_gateway" "gw" {allocation_id = "${aws_eip.eip.id}"subnet_id     = "${aws_subnet.public-subnet.id}"tags = {Name = "NATgateway"}}

Routing Table

Create a routing table for internet gateway so the instance can connect to the public, update and associate it with the public subnet.

resource "aws_route_table" "route-table" {vpc_id = "${aws_vpc.my_vpc.id}"route {cidr_block = "0.0.0.0/0"gateway_id = "${aws_internet_gateway.gw.id}"}tags = {Name = "rtable"}}
resource "aws_route_table_association" "associate_table" {subnet_id = aws_subnet.public-subnet.idroute_table_id = aws_route_table.route-table.id}

update the routing table of the private subnet, so that to access the internet it uses NAT gateway created for the public subnet.

Security group

Create custom security groups for WordPress and MySQL instances with requirement specific rules.

WordPress

The following ingress rules need to be kept in mind while creating the security group

  • HTTP port 80
  • HTTPS port 443
  • SSH port 22
resource "aws_security_group" "wp-security" {name        = "allow_http"description = "Allow http inbound traffic"vpc_id      = "${aws_vpc.my_vpc.id}"ingress {description = "http"from_port   = 80to_port     = 80protocol    = "tcp"cidr_blocks = [ "0.0.0.0/0" ]}ingress {description = "https"from_port   = 443to_port     = 443protocol    = "tcp"cidr_blocks = [ "0.0.0.0/0" ]}ingress {description = "ssh"from_port   = 22to_port     = 22protocol    = "tcp"cidr_blocks = [ "0.0.0.0/0" ]}egress {from_port   = 0to_port     = 0protocol    = "-1"cidr_blocks = ["0.0.0.0/0"]}tags = {Name = "allow_http"}}

MySQL

The following ingress rules need to be kept in mind while creating the security group

  • MySQL port 3306
  • SSH port 22
resource "aws_security_group" "mysql-security" {name        = "mysql_sg"description = "mysql security group"vpc_id      = "${aws_vpc.my_vpc.id}"ingress {description = "mysql server"from_port   = 3306to_port     = 3306protocol    = "tcp"cidr_blocks = [ "0.0.0.0/0" ]}ingress {description = "ssh"from_port   = 22to_port     = 22protocol    = "tcp"cidr_blocks = [ "0.0.0.0/0" ]}egress {from_port   = 0to_port     = 0protocol    = "-1"cidr_blocks = ["0.0.0.0/0"]}tags = {Name = "mysql_sg"}}

WordPress Instance

Launch an ec2 instance with WordPress setup (WordPress AMI) having the security group allowing port 80 so that client can connect to our web app. Also, attach the key to the instance for further login into it.

resource "aws_instance" "wordpress" {ami           = "ami-000cbce3e1b899ebd"instance_type = "t2.micro"key_name      = "SecKey"subnet_id     = "${aws_subnet.public-subnet.id}"security_groups = [ "${aws_security_group.wp-security.id}" ]availability_zone = "ap-south-1a"tags = {Name = "ec2 wordpress"}depends_on = [aws_instance.mysql]}

MySQL instance

Launch an ec2 instance with Mysql setup (MySQL AMI) already with the security group allowing port 3306 in the private subnet so that the WordPress instance can connect to it. Also, attach the key with the same.

resource "aws_instance" "mysql" {ami           = "ami-08706cb5f68222d09"instance_type = "t2.micro"key_name      = "SecKey"subnet_id     = "${aws_subnet.private-subnet.id}"security_groups = [ "${aws_security_group.wp-security.id}" ]availability_zone = "ap-south-1a"tags = {Name = "ec2 mysql"}}

These steps can be followed for the complete WordPress set by terraform, the same steps can also be manually followed directly on AWS.

To launch the infrastructure, follow the below steps in the terminal

  1. terraform init — used for provider plugins

2. terraform apply — used for creating infrastructure

Notice the following on AWS -

  • Instances launched
ec2 instances on AWS
  • NAT gateway
NAT gateway
  • Elastic IP
Elastic IP

Voilà!! WordPress infrastructure up and running on AWS with utmost security!!

WordPress on AWS

--

--