Project 3: Deploy a WordPress website on AWS.
We will deploy a scalable and highly available WordPress website on AWS.
Overview
This documentation provides a summary guide on hosting a WordPress website using AWS EC2 instances. We will be leveraging the 3-Tier VPC deployed in Project-1 to host this website.
The deployment of the WordPress website involved a comprehensive setup process encompassing various AWS services. The tasks ranged from establishing a robust VPC architecture with a single instance RDS setup, creating an Elastic File System for shared data, configuring EC2 instances, deploying WordPress, setting up an Application Load Balancer (ALB), managing DNS with Route53, integrating SSL certification, establishing a Jump Host for secure access, enabling HTTPS listeners, and implementing an Auto Scaling Group.
Architecture
The Architecture for this project includes the following AWS Services:
VPC (3-Tier-VPC with Security Groups)
Amazon RDS (MySQL 5.7)
Amazon EFS
Application Load Balancer
Auto-Scaling Group
My procedure is similar to that of Project-2. I made use of Terraform to deploy the VPC then clickops for deployment and configuration of the rest of the infrastructures.
Also, before starting this project, I already have my Domain Name and SSL Certificate.
VPC-Deployment
The Terraform script I used for the VPC deployment can be found here. The addition I made from Project-2 was to update the security group configurations with:
Security Group for Database on port 3306 (MySQL) with source from Webserver Security Group.
Added Security Group for Elastic File Storage on port 2049 with source from Webserver Security Group and The EFS Security Group itself. Then on SSH port 22 with source from the SSH Security Group.
RDS-Deployment
We will set up a MySQL database in the private data subnets. Below is the step-by-step overview of how to deploy our database.
The first step is to Create a Subnet Group - Subnet groups help us to place RDS instances in different subnets in different Availability Zones(AZs). In case one subnet or Availability Zone(AZ) goes down, our RDS can continue to operate in the remaining healthy AZ. When creating the Subnet Group, I selected our two AZs as well as the two private data subnets.
Next is to create the Database itself. I created it using the Standard creation method with MySQL engine. Since I was going to make use of Version 5.7, I selected the latest release available yet:
MySQL 5.7.44
. For this project, I made use of the Dev/Test Template. For cost reduction sake, I opted for a Single DB Instance under Availability and Durability. Next was to set the DB Instance Identifier, DB Name, DB Master Username and Password that will be used for authentication. Under Instance Class I made use of the 'Burstable classes' and toggle on Include previous generation classes, then chose the 'db.t3.micro
' instance. When setting up the Database connectivity, I selected the VPC we deployed as well as our pre-created Subnet Group then assigned theDatabase Security Group
we deployed using Terraform. I selected my preferred AZ to create the Database and selected 'Password authentication
' as my Database authentication method. To ensure our database is created, we had to specify theInitial Database Name
under Additional configuration before clicking onCreate database
.
EFS-Deployment
An Elastic File System (EFS) allows the webserver instances to pull the same data and configuration from the same location.
On the EFS dashboard, click on 'Create file system
' then 'Customize
'. Give the EFS a Name. I disabled Encryption to reduce cost since this is a dev environment. Under Tags give key as 'Name
' and set a Value for the Name. Click 'Next' to set up Network configurations.
Under Mount Target, select the two AZs as well as the respective Private Data Subnets then assign the EFS Security Group. Click 'Next' and leave 'File System Policy' as default then Review and click 'Create'.
Webserver Configuration
We need to get all our data into the EFS and to do this I made use of an EC2-Instance to serve as our development environment. I made use of Amazon Linux 2023 AMI and assigned it the Application Load Balancer, Webserver and SSH Security Groups.
WordPress-Set up
To set up WordPress, we need to install necessary packages like (PHP, Apache, MySQL) and configure file permissions. All these should be done on the EFS so we can have a central location for our configuration data. The script below was used to accomplish the necessary configurations:
#1. create the html directory and mount the efs to it and verify that efs is mounted
sudo yum update -y
sudo mkdir -p /var/www/html
sudo mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport my_efs_dns:/ /var/www/html
#2. install apache, apache utility tool and apache module that provides support for SSL/TLS encryption.
sudo yum install -y httpd httpd-tools mod_ssl
sudo systemctl enable httpd
sudo systemctl start httpd
#3. install php on Amazon Linux 2023
sudo yum install -y php php-common php-pear
sudo yum install -y php-{cgi,curl,mbstring,gd,mysqlnd,gettext,json,xml,fpm,intl,zip}
#4. install mysql5.7
sudo rpm -Uvh https://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm
sudo rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022
sudo yum install mysql-community-server -y
sudo systemctl enable mysqld
sudo systemctl start mysqld
#5. set permissions
sudo usermod -a -G apache ec2-user
sudo chown -R ec2-user:apache /var/www
sudo chmod 2775 /var/www && find /var/www -type d -exec sudo chmod 2775 {} \;
sudo find /var/www -type f -exec sudo chmod 0664 {} \;
sudo chown apache:apache -R /var/www/html
#6. download wordpress files
wget https://wordpress.org/latest.tar.gz
tar -xzf latest.tar.gz
sudo cp -r wordpress/* /var/www/html/
#7. create the wp-config.php file
sudo cp /var/www/html/wp-config-sample.php /var/www/html/wp-config.php
#8. edit the wp-config.php file
sudo sed -i "s/'database_name_here'/'my_db_name'/g" /var/www/html/wp-config.php
sudo sed -i "s/'username_here'/'my_db_username'/g" /var/www/html/wp-config.php
sudo sed -i "s/'password_here'/'my_db_password'/g" /var/www/html/wp-config.php
sudo sed -i "s/'localhost'/'my_rds_endpoint'/g" /var/www/html/wp-config.php
#9. restart the webserver
sudo service httpd restart
Before running the script, be sure to replace the following details with your own values:
#1 - my_efs_dns - Replace with the DNS value from your EFS that looks like
fs-0e64746745e1f0.efs.us-east-1.amazonaws.com
#8 - my_db_name - Replace with your database name
#8 - my_db_username - Replace with your database username
#8 - my_db_password - Replace with your database password
#8 - my_rds_endpoint - Replace with your database endpoint that looks like
mydb.adcem8cumi94.us-east-1.rds.amazonaws.com
After the script has been completely executed, using the development environment ec2 instance's public IP, we can access and complete the WordPress set-up via the browser. Input "site title, WordPress username, password and email address" then click on Install WordPress
.
Set up Application Load Balancer (ALB)
Firstly, we have to launch an ec2-instance in each of the private app subnets. Make use of the same AMI we used for our development environment, assign the Webserver security group and bootstrap it with the script below, using user data.
#!/bin/bash
yum update -y
sudo yum install -y httpd httpd-tools mod_ssl
sudo systemctl enable httpd
sudo systemctl start httpd
sudo yum install php php-common php-pear -y
sudo yum install php-{cgi,curl,mbstring,gd,mysqlnd,gettext,json,xml,fpm,intl,zip} -y
sudo rpm -Uvh https://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm
sudo rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022
sudo yum install mysql-community-server -y
sudo systemctl enable mysqld
sudo systemctl start mysqld
echo "my_efs_dns:/ /var/www/html nfs4 nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 0 0" >> /etc/fstab
mount -a
chown apache:apache -R /var/www/html
sudo service httpd restart
Before running the script, be sure to replace 'my_efs_dns' with the DNS value from your EFS that looks like fs-0e64746745e1f0.efs.us-east-1.amazonaws.com
.
The next step is to create our Application Load Balancer mapped to the two public subnets and then create a Target group of type "Instance" in the private app subnets. Select the two instances in the private app subnets and include them in the Target group. Add a listener for the Target group on HTTP port 80 with health check success code 200,301,302. Link the Application Load Balancer to the Target group and after it has been successfully provisioned, copy the Application Load Balancer DNS and paste it into a browser to reach the WordPress website.
We can log in to our WordPress backend using the Application Load Balancer DNS with /wp-admin i.e., https://alb-dns/wp-admin. Change the WordPress and Site Address from the public IP of the development environment server to the ALB-DNS under Settings - General - then click on 'Save Changes'.
Create A-Record
On the Route-53 dashboard, navigate to the hosted zones and click on our existing domain name. Click on Create record - enter "www" as the subdomain and leave A as the record type. Toggle on the Alias button to select Alias to Application and Classic Load balancer
then select the ALB region. Select the ALB and click 'Create records'.
We should now be able to reach our website using our domain name.
Set up HTTPS Listener
Navigate to our ALB and under Listeners, add a new listener for HTTPS on port 443 and select our SSL Certificate under ACM. Edit the existing HTTP listener and change it from forward
to redirect
. Redirect it to HTTPS on port 443.
SSH into one of the ec2-instances in the private app subnet. Note that we cannot SSH to instances in the private app subnet directly from the internet. We can make use of the Development Environment server to SSH into instances in the private app subnets. After gaining access to one of the servers, edit the /var/www/html/wp-config.php
file using vi, vim or nano. Search for this line: // Database settings - You can get this info from your web host //
then add the SSL settings script below just above that line.
/* SSL Settings */
define('FORCE_SSL_ADMIN', true);
// Get true SSL status from AWS load balancer
if(isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
$_SERVER['HTTPS'] = '1';
}
Save the file and type our domain name into a browser to access our website. It should now display as a secure website with the lock icon. Use /wp-admin
to access the backend and update the WordPress and Site Address from the ALB DNS to our domain name. We can now terminate the two instances in the private app subnets.
Set up Auto-Scaling Group
We will create a launch template and use it to set up an auto-scaling group with a desired capacity of two running instances, a minimum of one and a maximum of 4 instances in the private app subnets.
Launch Template: On the ec2 dashboard, navigate to Launch Template and create a launch template with the same configuration we used for the instances we created in the private app subnets. Make use of the same user data script. Remember to Check 'provide guidance …' when setting up the template.
Auto-Scaling Group: Navigate to Auto-Scaling Group and set it up by using the created Launch Template. Select the Private app subnets as well as our already created ALB and Target group. Check Elastic Load Balancer under health check and specify the group size as 1- minimum, 2-desired and 4-maximum. Configure SNS topics for alerting and add a tag for the Auto-scaling group. Then review and create.
At this point, you can install preferred themes to customize your WordPress website to your taste and requirements.
Conclusion
This systematic approach ensures high availability, scalability, and security for the WordPress website. By leveraging AWS resources effectively, the project achieved a resilient infrastructure capable of handling varying loads while maintaining accessibility and reliability. Moreover, the incorporation of automation through scripts and templates streamlines future scaling and deployment efforts, enhancing the overall efficiency of the system.
Cleaning up our Deployments
We can delete our resources in the following order:
First, destroy Jump Host, Auto-Scaling Group, Launch Template, Application Load Balancer, Target Group, RDS, EFS and database subnet group. Then delete the A-Record.
After all these, we can then make use of terraform to destroy our VPC services.
Acknowledgements
Credits to AOSNOTE for the project guidance.