Creating and launching sample webserver(with Backend DB)in AWS using Terraform.

Saumik Satapathy
7 min readJul 27, 2020

In my previous post, I created a production-ready VPC using terraform(Link). In this demo, we will be implementing production-ready servers using terraform. Just a brief summary of what we are going to achieve in this demo,

First, we will instruct our Terraform that the below code is to create Infrastructure in AWS . To achieve this we need to create a provider.tf file where we will declare the provider. So, in backend terraform will download the required files for the aws to launch the resources. We will pass the region as a variable which we will declare later.

The content of provider.tf is as below,

provider "aws" {
region = var.region
}

As our vpc and subnets are created earlier we will create a variable file called variable.tf and declare them. So we can call them where ever we required. Also, we will declare our AWS region as well.

The content of variables.tf is as below,

variable "region" {
default = "ap-south-1"
description = "AWS Region"
}
variable "vpc_id" {
default = "vpc-0feaa21ebf38d2ae6"
}
variable "public_subnet_1_id" {
default = "subnet-051834cfc5d3a418c"
description = "Public Subnet 1 ID"
}
variable "public_subnet_2_id" {
default = "subnet-0ba7500feadae8dfd"
description = "Public Subnet 2 ID"
}
variable "public_subnet_3_id" {
default = "subnet-0c584f40c260d270a"
description = "Public Subnet 3 ID"
}
variable "private_subnet_1_id" {
default = "subnet-08feb8b7fa670a5db"
description = "Private Subnet 1 ID"
}
variable "private_subnet_2_id" {
default = "subnet-00303f87b29feeebd"
description = "Private Subnet 2 ID"
}
variable "private_subnet_3_id" {
default = "subnet-06cc1daab419a03f7"
description = "Private Subnet 3 ID"
}

2. Creating two security groups, One is for Internet-facing instance i.e. wordpress and another for the Database server i.e. MySQL. So, let's write the terraform code. we will name the file as wordpress-sg.tf and mysql-sg.tf respectively.

In the wordpress-sg.tf file which is meant to create a security group for WordPress, we will open HTTP(80) and SSH(22) to all. The reason behind that is we will open the webpage for all the customers across the globe also we need to SSH into the instance for required modification.

The content of wordpress-sg.tf is as below,

resource "aws_security_group" "ec2_public_security_group" {
name = "wordpress-sg"
description = "Security Group for public access"
vpc_id = var.vpc_id
ingress {
from_port = 80
protocol = "TCP"
to_port = 80
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 22
protocol = "TCP"
to_port = 22
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
protocol = "-1"
to_port = 0
cidr_blocks = ["0.0.0.0/0"]
}
}

After creating the security group for wordpress let’s create the security group for Mysql. We will give that file a name as mysql-sg.tf for our identification.

The content of mysql-sg.tf is as below,

resource "aws_security_group" "ec2_private_security_group" {
name = "mysql-sg"
description = "Security Group allowing only public subnet instances"
vpc_id = var.vpc_id
ingress {
from_port = 0
protocol = "-1"
to_port = 0
security_groups = ["${aws_security_group.ec2_public_security_group.id}"]
}
egress {
from_port = 0
protocol = "-1"
to_port = 0
cidr_blocks = ["0.0.0.0/0"]
}
}

In mysql-sg.tf we are allowing all ports to our wordpress security group. That means any instance with that security group can access to Mysql server. No outsider is allowed to get into MySQL server. It’ll add another layer of security.

We will now create the key pairs which can be used to SSH into the instances.

$ ssh-keygen -t rsa -f mykey

It will create a key pair named mykey and mykey.pub. We will create a Terraform file to upload the key to AWS. The content of key.tf is as below,

resource "aws_key_pair" "key" {
key_name = "mykey"
public_key = file("mykey.pub")
}

Now, it’s time to create our last and final resources which is two EC2 Instances. One for wordpress and another for mysql. The content of wp-instance.tf is as below. It will create an EC2 instance and install WordPress in it.

resource "aws_instance" "my_public_instance" {
ami = "ami-0732b62d310b80e97"
instance_type = "t2.micro"
key_name = "mykey"
subnet_id = var.public_subnet_1_id
associate_public_ip_address = true
vpc_security_group_ids = [aws_security_group.ec2_public_security_group.id]
private_ip = "192.168.1.5"
connection {
type = "ssh"
user = "ec2-user"
private_key = file("mykey")
host = aws_instance.my_public_instance.public_ip
}
provisioner "file" {
source = "mykey"
destination = "/home/ec2-user/mykey"
}
provisioner "remote-exec" {
inline = [
"chmod 0400 /home/ec2-user/mykey",
]
}
provisioner "file" {
source = "wordpress.sh"
destination = "/home/ec2-user/wordpress.sh"
}
provisioner "remote-exec" {
inline = [
"chmod +x wordpress.sh",
"./wordpress.sh",
]
}
tags = {
Name = "WordPress"
}
}

In the previous terraform file we’re passing a shell script named wordpress.sh . It will install WordPress in the EC2 instance. The content of thewordpress.sh is as below,

#!/bin/bash
sudo setenforce 0
sudo sed -i 's/enforcing/disabled/g' /etc/selinux/config
sudo yum install httpd php php-common php-mysqlnd php-mbstring php-gd -y
sudo sed -i 's/AllowOverride none/AllowOverride all/g' /etc/httpd/conf/httpd.conf
wget https://wordpress.org/wordpress-4.9.tar.gz
sudo tar xvzf wordpress-4.9.tar.gz
sudo mv wordpress/* /var/www/html/
sudo chown -R apache:apache /var/www/html/
sudo systemctl restart httpd

The above script will install PHP and HTTPD which are pre-requites for WordPress. Then it will download the WordPress installation bundle and unzip that. After unzipping it will put the content to \var\www\html which is the default location for Apache Web Server. Then it will restart the HTTP daemon.

The final step is to create a Terraform file for installing MySQL and creating a DataBase which will be used for WordPress. The content of ms-instance.tf is like below,

resource "aws_instance" "my_private_instance" {
ami = "ami-0732b62d310b80e97"
instance_type = "t2.micro"
key_name = "mykey"
subnet_id = var.private_subnet_1_id
vpc_security_group_ids = [aws_security_group.ec2_private_security_group.id]
private_ip = "192.168.4.5"
user_data = <<EOF
#!/bin/bash
sudo yum update -y
wget https://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm
sudo yum install mysql-community-release-el7-5.noarch.rpm -y
sudo yum install mysql-server -y
sudo systemctl start mysqld
sudo systemctl enable mysqld
mysql -uroot <<MYSQL_SCRIPT
CREATE DATABASE wordpress;
CREATE USER 'wordpress'@'%' IDENTIFIED BY '12345';
GRANT ALL ON wordpress.* TO wordpress@'%' IDENTIFIED BY '12345';
MYSQL_SCRIPT
EOF
tags = {
Name = "MySQL"
}
}

Now, it’s time to create the output file which will display the required IPs for further operation on Web Console. The outputs.tf file content is as below,

output "wp_instance_public_ip" {
value = aws_instance.my_public_instance.public_ip
}
output "ms_instance_private_ip" {
value = aws_instance.my_private_instance.private_ip
}

The coding part is now completed. Let’s run the terraform apply and see the output. But before that, we have to run terraform init to download the required plugins. It’s always advisable to run terraform validate and terraform plan before firing the terraform apply command. It will show the errors and we can rectify them.

$ terraform init
$ terraform validate
$ terraform plan
$ terraform apply

After running the apply command, it will give the public IP of WordPress instance. In a browser put that IP and hit ‘Enter’. A WordPress Configuration page will come.

terraform apply command output

Go to the Web browser and put the WordPress Instance Public IP and hit ‘Enter’.

A WordPress configuration page will open. Choose your language. In this demo I choose English (United States). Then click on Continue.

In ten next page just click on Let's Go.

Put the Database Name, User Name and password we provided during the MySQL server creation time. Put the MySQL instance private IP in the Database host field.

In the next page, click on Run the Installation tab.

After clicking the Run the Installation tab, it will open and page to set the WordPress page administration details. Fill the form and click on Install Wordpress

WordPress Administration page setup
Login page for the WordPress admin

If you want to set up a new page or modify existing then log in the WordPress page or exit.

In a new tab put the Public IP of the WordPress instance and a Sample page will be displayed.

Sample page

Few points to note;
1. The MySQL instance is in a private subnet so opening all ports won’t be a security threat.
2. For automation purpose, we need to fix the private IP of both instances. In MySQL instance we created a DB which is only accessible from WordPress instance. In the WordPress page setup, we need to pass the MySQL private IP.

Complete terraform source code can be found in the GitHub,
https://github.com/saumik8763/wp-aws-terraform

--

--

Saumik Satapathy

A passionate software Engineer with good hands on experience in the field of DevOps/SRE. Love to share knowledge and intersted to learn from others.