Public WordPress and Private Database on AWS EC2

This article sets up a public WordPress site and a private SQL Database for the security of the data. This set up is made on AWS Cloud using multiple services.

A Website is a face, the front-end of your business. The website is made as creative as possible because all the clients/users explore the site all the time. But as important as the front-end, the back-end is equally important. The back-end consists of all the important data such as login credentials, search information, etc. of the client. If the database gets compromised all the data will be mishandled and the reputation of your business goes down.

So a more accurate setup for such an infrastructure would be:

  • WordPress site launched in the Public world where anyone can access it.
  • MySQL Database launched in the Private world where only the members of the “Storage Team” can access it.
  • Also with all the instances launched, proper Firewall rules need to be set so that clients can hit only on specified ports and services and no malicious activities can be done.

I have created this setup on AWS Cloud. The steps followed are listed below:

  • Set the provider.
  • Create a Virtual Private Cloud (VPC).
  • Create 2 Subnets in this VPC:

Public Subnet [Accessible to the Public World]

Public Subnet [Accessible to the Public World]

  • Set the Public Subnet Firewall rules so that client can only hit on port 80 only. This will improve security.
  • A private Subnet where a Database is created should have these particular Firewall rules:

Allow entry in the Database from the Website only to store data.

The database can go to the Internet for any updates/security patch update.

  • Then finally check whether the data is going in our Database or not i.e. whether or not WordPress connected to our Database.

Let’s start by building the code.

Step 1 — Setting the Provider

First, we set up the provider for downloading the plugins required for the AWS Cloud Platform.

Profile is set so that the Terraform code automatically picks up credentials from the local system without passing it through code.

The profile can be set using the following command:

aws configure --profile  profilename

Step 2 — VPC, Subnets, Gateway, Routes, Rules

I have created a VPC with the Private IP CIDR Block 192.168.0.0/16.
Then enabling the DNS Support and Hostname is important so that auto Public IP Allocation for the instance can be done.

Public Subnet

This is the Public Subnet I have created in Availability Zone ap-south-1a. I have set the value of map_public_ip_on_launch as true so that when an instance is launched in this subnet a Public IP is associated with it. Using this IP, clients will be able to hit the instance to see the Web Page. Also, I have set the CIDR Block value according to the one specified while creating the VPC.

Internet Gateway, Route Table and Route Association

First I have created an Internet Gateway. This will be the common gateway through which traffic would come into the Instance i.e. Public world to the Private world. Internet Gateway provides DNAT: Destination Network Address Translation. But by default, the Internet Gateway also provides service for SNAT. This means that the instance can also go to the Internet i.e. Private to Public world

Then I have created a Route Table with the common gateway as the above created “Internet Gateway”.

Then finally associate the Route Table with the Public Subnet using its ID. After associating we have fixed the subnet to use only a particular Route Table.

Private Subnet

This is the Private Subnet I have created in Availability Zone ap-south-1b. I have set the value of map_public_ip_on_launch as false so that when an instance is launched in this subnet a Public IP is not associated with it. I have done this on purpose because in this subnet I will be launching the MySQL Database and I don’t want anyone can get into my Database and compromise the data. This is done to keep the MySQL Database in the Private world.

NAT Gateway, Route Table and Route Association

First I created an Elastic IP. An EIP address is a reserved public IP address that can be assigned to an EC2 instance in a particular region until you choose to release it.

This will be used in NAT Gateway. A NAT Gateway is a special case where we only want the instance to go to the internet. We don’t want to allow outside traffic from the Public world into the instance. NAT Gateway provides SNAT: Source Network Address Translation.

To create the NAT Gateway I have specified the EIP ID and the ID of the Public Subnet. This means I have launched the NAT Gateway in the Public Subnet.

NAT Gateway takes the instance out to the Public World and only Public Subnet has this ability. So NAT Gateway is always launched in the Public Subnet.

Then I have created the Route Table, with the destination as 0.0.0.0/0, which means anywhere in the world and the Gateway is the NTA Gateway.

Then finally associated the Route Table with the Private Subnet so that when I launch the instance (Database) in this subnet it has connectivity to the Public World and also at the same time no one can come into this instance, because it is isolated.

Step 3 — Create the EC2 Instance: WordPress

First, create the Security Group for the WordPress EC2 Instance.

In the security group mainly 2 things have to be set: Ingress and Egress.

Ingress means the traffic that is coming into our website. We need to specify this, keeping in mind what ports we want to keep open. I have kept open 2 ports: SSH, and HTTP.

  • SSH for connecting to the remote instance so that we can configure the instance for use as WordPress.
  • HTTP so that traffic can hit on the website.

Egress has been set to all ports so that outbound traffic originating from within a network can go outside to the Public World.

EC2 Instance Launch: WordPress

This is the most important part. Here I have created the WordPress Instance. The following are some points to be kept in mind:

  • I have specified an AMI ID and an instance_type to be used for the instance.
  • Then the ID of the Security Group and the Subnet are specified to be used in the instance. A key is also provided for SSH to be done on the remote system.
  • Then a null resource is created for doing a “remote-exec” on the instance to configure it as a WordPress instance.
  • I have created a docker setup of WordPress inside the EC2 Instance.

Step 4 — Create the EC2 Instance: MySQL Database

I have created the Security Group for MySQL EC2 instance.

In Ingress, I have just opened the port 3306, and that too only for the WordPress instances. This is done by specifying the Security Group ID of the WordPress Instance. By this, I am telling MySQL Instance to allow the instances that are using the Security Group whose ID is specified.

For egress, I have set as 0.0.0.0/0 as the destination which means that the SQL Instance can go anywhere in the world in the Public World (using NAT Gateway).

EC2 Instance Launch: MySQL

Now finally I have created the MySQL Instance. The following are some points to be kept in mind:

  • I have specified the same AMI ID and an instance_type to be used for the instance.
  • Then the ID of the Security Group and the Subnet are specified to be used in the instance.
  • Then I am passing the data in “user_data”. I am not doing remote exec here because for that I will have to open port 22 for SSH which will be unsafe for the Database Instance.

Now I will explain how the flow of the setup goes:

  • First, the VPC, Subnet, and Routes are created.
  • Next, only the WordPress Instance setup is created.
  • Then the MySQL Setup is created and also the user_data is passed. This makes the MySQL Database active and has an IP, Hostname, and Database name.
  • Finally, the WordPress remote-exec is done which uses the MySQL Database details.

Bonus: Opens on Chrome automatically when infrastructure is setup

This part depends on the “WordPress — MySQL Connection”, after the connection is made it will launch the site on chrome.

(PS. To launch chrome from Command Prompt on Windows, you have to set the Environment Variable PATH for Chrome Application.)

Output:

Final Output

This is just how the WordPress site gets deployed and is successfully opened.

Since I have deployed my own MySQL Database, it is important to check whether or not WordPress is using my database or not.

To prove this there are multiple ways:

  • Go inside the MySQL Database and check if the WordPress site has created some tables or not.

This can’t be done because there is no way to go inside the MySQL Database. This can be done only if either SSH is allowed on the instance and it is in the Public Subnet. But for Security, I have closed port 22 — SSH.

  • Check the settings of WordPress Site and match the Private IP of the database it is using with the EC2 Instance I launched.
IP Match

The Database IP of the WordPress Site and the Private IP of the EC2 Instance is the same.

So WordPress site is using our Database.

You can find the code on my GitHub.

Worked in collaboration with Ashish Kumar.

Automation Tech Enthusiast || Terraform Researcher || DevOps || MLOps ||

Get the Medium app