Creating and launching sample webserver(with Backend DB)in AWS using Terraform.
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.
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
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.
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