Highly Available and Secured WordPress on AWS: A Comprehensive Guide

Matthew
16 min readJun 23, 2023

--

Love WordPress? Ready for a cloud adventure? Join me as I guide you through deploying a highly available and secured WordPress on AWS for less than $1 using the AWS free tier.

As a certified AWS Solution Architect, I’ve crafted simple step-by-step instructions and touched on as many AWS services as possible for your hands-on experience.

I hope you will all succeed in unleashing the full power of cloud computing and elevating your career to new heights!

The Concept

Bid farewell to unreliable all-in-one LAMP servers for WordPress. Our new solution ensures high availability by deploying across multiple Availability Zones with Auto Scaling for failover.

The newly designed architecture is supported by a high-availability RDS database and a robust EFS file system, which will seamlessly connect to WordPress instances in the Auto Scaling Group. We will further optimize performance with RDS Read Replica and ElastiCache for speedy database access and content caching.

We will place all critical resources in private subnets for security and only allow connections from trusted AWS resources. A resilient Application Load Balancer will distribute traffic to secured WordPress servers. To improve load time and enforce SSL connections, we will utilize CloudFront and even connect WordPress with our own domain via Route 53.

Lastly, for server maintenance, in each public subnet, we will place a Bastion host for SSH access and another NAT Gateway to allow Internet connection/updates for WordPress instances well-protected behind in the private subnet.

Let’s get started!

Step 1 — Setup VPC and Subnets

In this demo, I chose US-West-1 (North California), but you can pick up any region that is near you for fast access and low latency.

Remember to deploy in at least 2 Availability Zones, with a minimum of one private and one public subnet in each. You can also limit the CIDR for this demo to reserve IPv4 addresses for other purposes.

Step 2 — Deploy a Bastion host in a public subnet

A Bastion host will be deployed in a public subnet, and through this Bastion host, we will SSH to WordPress servers placed in private subnets.

Go to AWS EC2 and create a free tier Amazon Linux instance. For the Network setting, remember to place it in a public subnet and enable Auto-assign public IP so that we can connect to the Bastion host instance.

There are several ways to connect to your Bastion host, and my preferred method for this demo is via EC2 Instance Connect in the browser. However, if you like popular SSH clients such as Terminal (for Mac) or Putty (for Windows), then you need to prepare 2 things:

  • In Bastion host’s Security Group, allow SSH inbound from the Internet (0.0.0.0/0), or more securely from your own public IP.
  • Create a Key pair for the Bastion host and save it to your computer.

Step 3 — Deploy a temporary WordPress instance in a private subnet

We will deploy this temporary EC2 instance and install all the software with the necessary configurations to make a perfect WordPress server. Then we will create a launch template from this server for Auto Scaling.

Just go to AWS EC2 and create a free tier Amazon Linux instance. Remember to deploy it in a private subnet of the same Availability Zone with the Bastion host. Then we create a new Security Group for all WordPress servers that allow SSH inbound connection, with Source from the Security Group of the Bastion host.

We will install all software and add more rules to WordPress servers’ Security Group later when we add more AWS services such as RDS and EFS.

Remember that you MUST create a Key pair for WordPress servers and save it to your computer. This key will be used later for SSH access from the Bastion host.

Step 4 — Create a NAT Gateway

At the moment, the WordPress instance in the private subnet only can be SSH from the Bastion host, but the instance itself is unable to connect to the Internet to download software or make critical updates.

To solve the issue, we can either deploy a NAT instance or a NAT Gateway. The latter is more popular because it is highly available, more robust, and managed by AWS.

In our demo, we will deploy a NAT Gateway in the same public subnet with the Bastion host and assign an Elastic IP for the NAT Gateway.

After deploying NAT Gateway, just remember to configure the existing route table of the private subnet that hosts the temporary WordPress server. Add a rule to allow Internet connection (Destination 0.0.0.0/0) via the newly created NAT Gateway.

To achieve high availability in your architecture, you can consider creating an additional NAT Gateway in the remaining public subnet. Configure the route table of the private subnet in the same Availability Zone to direct traffic through this new NAT Gateway. This redundancy ensures that if one NAT Gateway becomes unavailable, the other one can handle the traffic seamlessly, maintaining high availability for your system.

Step 5 — Create an RDS Database

The database is a critical component in WordPress to store login credentials, pages, posts, etc. Relational databases such as MySQL or PostgreSQL are popular choices for WordPress.

Before creating the database, we will prepare a dedicated RDS Security Group. Simply create a new Security Group, and in the inbound rules, select MYSQL/Aurora with Source from the Security Group of the WordPress app. With this option, only WordPress servers can access the RDS.

Now we go to RDS and create a Database. In this demo, we will choose free-tier RDS MySQL and remember to save the database credentials, such as the Master username and Master password for later use.

To make it more secure, disable public access and deploy the RDS database in the same Availability Zone with the Bastion host and temporary WordPress instance.

It will take a while for the database creation. Meanwhile, we can now prepare a shared drive for the WordPress application.

Step 6 — Create an EFS shared drive

As we leverage Auto Scaling to adjust the number of WordPress instances based on demand dynamically, it is advantageous to utilize an EFS shared folder to store all configurations and data for the WordPress application. This ensures that any new server joining the Auto Scaling Group can immediately access the EFS shared folder and the RDS database to handle incoming traffic efficiently.

First, we need to create a new Security Group for EFS and allow incoming NFS traffic directly from the Security Group of WordPress servers.

After that, we just create our own EFS. Remember to deploy on private subnets and attach to the newly created EFS’s Security Group.

Creating the EFS may require some time, but once it’s completed, you’ll receive the essential information to attach the EFS drive to our WordPress instance. Make sure to take note of the highlighted mounting DNS information, as you will need it for future steps.

Step 7 — Prepare the WordPress instance

With the completion of the essential infrastructure setup, including the Bastion host, temporary WordPress server, RDS database, and EFS shared drive, we are now ready to create an impeccable WordPress server!

To establish an SSH connection with the WordPress server in the private subnet, you will require two things:

  1. The private IP of the WordPress server, and
  2. The previously saved WordPress key pair on your computer.

To access the key pair, simply open it with any text editor. In my case, I use TextEdit on my Mac to view the content. Copy the entire key from the file.

Now, connect to the Bastion host instance via EC2 Instance Connect in the browser.

Insert the following command to create a new key pair in the Bastion host terminal. Paste the copied key pair and then save it.

nano app-key.pem

After recreating the key pair, we will update its permissions and then SSH to the temporary WordPress instance using its private IP. Make sure to replace “10.0.8.57” with the private IP of your WordPress instance.

sudo chmod 400 app-key.pem
ssh -i "app-key.pem" ec2-user@10.0.8.57

Next, we’ll proceed with updating the instance and installing essential software, including Apache, PHP, and MySQL.

sudo yum update -y

sudo yum install php -y
sudo yum install php-mysqli -y
sudo yum install mariadb105 -y

Once completed, we’ll activate these services and configure them to start automatically after a system restart.

sudo systemctl start httpd
sudo systemctl enable httpd

sudo systemctl start php-fpm
sudo systemctl enable php-fpm

Then we will create some permits to access the Apache public folder.

sudo usermod -a -G apache ec2-user
sudo chown -R ec2-user:apache /var/www/html
sudo chown -R apache:apache /var/www/html

Using the recently created EFS shared drive, we will proceed to mount it to the server’s root folder for the website. Make sure to replace “fs-020a682c5ba2f0fc3.efs.us-west-1.amazonaws.com” with the DNS of your EFS folder. If you’re unsure where to locate it, refer to the instructions at the end of Step 6.

sudo mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport fs-020a682c5ba2f0fc3.efs.us-west-1.amazonaws.com:/ /var/www/html/

To ensure that the EFS shared folder is automatically mounted to the WordPress server after a restart, enter the following command.

sudo nano /etc/fstab

Append the following line to the end of the file and save it. Make sure to replace “fs-020a682c5ba2f0fc3.efs.us-west-1.amazonaws.com” with the DNS of your EFS folder. If you’re unsure where to find it, refer to the end of Step 6.

fs-020a682c5ba2f0fc3.efs.us-west-1.amazonaws.com:/ /var/www/html/ nfs defaults,_netdev 0 0

To verify that the EFS drive has been successfully mounted, enter the following command in the terminal. You should observe the EFS drive being mounted to “/var/www/html,” which represents the root folder of the website.

df -T -h

Next, we will download WordPress, unzip the downloaded file, and install it on the temporary server using the following commands.

wget https://wordpress.org/latest.zip
unzip latest.zip
sudo cp -R wordpress/* /var/www/html/

Now, the preparation for the WordPress server is complete. However, before exiting the Bastion host, we need to access RDS and create an initial database.

Insert the following command in the Bastion host terminal and replace “wp-db.cb7yjv0w5dmw.us-west-1.rds.amazonaws.com” with your RDS endpoint and “admin” with your RDS Master username if you have chosen a different one

mysql -h wp-db.cb7yjv0w5dmw.us-west-1.rds.amazonaws.com -P 3306 -u admin -p

After typing in the RDS Master password, please enter the following SQL commands. This command will create a database named “project” as the first WordPress database. Feel free to replace “project” with your preferred name if you’d like.

create databases project;
show databases;

Step 8: Create a launch template for Auto Scaling

Now that we have set up a flawless WordPress instance, let’s proceed to create a launch template for future Auto Scaling.

Simply select the temporary WordPress instance, in “Actions,” choose “Image and Templates,” and then select “Create image.”

It will take a while to create a golden image of the temporary WordPress instance. Once it is done, go to EC2 and create a launch template.

In the “Application and OS Images” option, select “My AMIs” and then choose your newly created WordPress instance image.

For the instance type, choose t2.micro as it is eligible for Free tier. Select the existing WordPress key pair for the launch template and the existing Security Group for the WordPress instance. If you don’t remember the detail, go back to Step 3.

Step 9 — Deploy an Auto Scaling group

Now that we have our WordPress launch template, launching WordPress instances is a breeze. Simply navigate to the EC2 console and select “Auto Scaling Groups.” From there, choose the recently created launch template. This allows you to effortlessly launch multiple WordPress instances with ease.

In the “Network” option, select the private subnets in both Availability Zones. This ensures that the new WordPress instances will be launched in those specific subnets, providing the desired network configuration.

In the “Group size” configuration, set the desired capacity to 2. This will ensure that 2 instances are launched, with one instance in each private subnet.

As for scaling policies, you have the flexibility to choose based on your specific requirements. If you prefer, you can leave it as “None” so that the default scaling policy will rely on the instance health check.

Please note that it may take some time for the two new WordPress servers to be provisioned in the private subnets.

Once the process is complete, you will see a total of four instances in the EC2 dashboard. These include the two instances in the Auto Scaling group, the Bastion host, and the temporary WordPress instance that was created earlier in Step 3.

You can now terminate the temporary WordPress instance by accessing its terminal. You can also create an Auto Scaling group for Bastion hosts to make them highly available as well.

Step 10 — Create an Application Load Balancer and connect with the Auto Scaling group

Now that we have completed the back-end setup of our WordPress application, the next step is to connect it with a Load Balancer.

To do this, we will create a Target Group for the Load Balancer. Choose “Instances” as the Target type and “HTTP” as the listening protocol. If desired, we can also add the “HTTPS” protocol later.

Please note that when creating the Target Group for the Load Balancer, make sure not to select any running instances as targets. This is because these instances may be terminated in the future as we scale up or down our Auto Scaling group. Instead, we will have the option to attach the Auto Scaling group to the Load Balancer’s target, which will be shown later in the process.

Now, create a new Security Group for Load Balancer, allowing inbound rules for HTTP and HTTPS traffic.

Next, let’s create an Application Load Balancer. Choose the Internet-facing scheme and ensure that the Load Balancer is placed in all public subnets.

Select the recently created Security Group for the Load Balancer and configure it to listen to both HTTP and HTTPS connections.

After finishing the setup for the Application Load Balancer, go back to the existing Auto Scaling group and attach it to the newly created Load Balancer.

To allow incoming traffic from the Load Balancer, navigate to the Security Group associated with the Auto Scaling group. Add inbound rules for both HTTP and HTTPS protocols, specifying the source as the Security Group of the Load Balancer.

To test the new Load Balancer, copy its endpoint and paste it into your browser. You should see a success screen confirming that the connection was successful.

If you prefer to connect with your own domain and cache with CloudFront, you can leave it as it is and proceed with the next steps.

Step 11 — Create a CloudFront distribution

To set up CloudFront, navigate to the service and choose the newly created Application Load Balancer as the Origin Domain. Select HTTP as the default option for the listener protocol.

For the Viewer setting, select HTTP and HTTPS, or you can choose to redirect HTTP to HTTPS. However, if you opt for the redirect option, you will need to request an SSL certificate.

Make sure to choose “GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE” as these methods allow the WordPress admin user to write, post, and configure the website.

After the setup is complete, you will receive a CloudFront distribution domain name that you can use to access your WordPress website.

If you want to connect your own domain, which is managed by Route 53, with the CloudFront distribution, you need to add that domain name in the “Alternative domain names” field.

Step 12 — Register CloudFront distribution with Route 53

When registering your own domain, you have the option to use Route 53 as your domain management service or choose a different third-party provider.

If you decide to use Route 53, it’s important to note that you should only purchase domains that are supported by Route 53 for seamless integration and management.

To create a Hosted Zone for your domain registered with a third-party provider, please follow these instructions:

Once you have added your Hosted Zone, select your domain and create a new record using the simple routing policy.

Choose the A Record type and direct the traffic to your newly created CloudFront distribution.

Congratulation, you made it!

Insert your domain name into your browser and try your own WordPress application.

Enter all the previously gathered information into the respective fields. For the database host, enter the RDS endpoint that you obtained earlier.

Now you have the ability to create your very own WordPress blog.

Feel free to explore and experiment with your WordPress blog. You can download new themes, test the functionality of the NAT Gateway, and create posts to customize your blog.

To test high availability, you can manually terminate one of the WordPress instances and observe how the Auto Scaling group automatically scales up to maintain the desired capacity.

Enjoy exploring the features and capabilities of your WordPress server!

There are several useful WordPress plugins you can try to enhance your cloud architecture further:

  1. WP Offload Media: This plugin allows you to host your images and media files in Amazon S3, which provides scalable and durable storage. By offloading your media to S3, you can reduce the load on your WordPress server and improve overall performance.
  2. HyperDB: With this plugin, you can configure your WordPress site to filter database read and write operations between the RDS Master and Read Replica instances. This helps distribute the database load and improves read scalability, especially for content-heavy websites.
  3. W3 Total Cache: This plugin integrates your WordPress site with Amazon ElastiCache, a fully managed in-memory data store. By caching frequently accessed data, such as database queries or rendered pages, in ElastiCache, you can significantly improve the performance and response times of your WordPress application.

By leveraging these plugins, you can further optimize your architecture and enhance the scalability, performance, and resilience of your WordPress servers on AWS.

I’m glad that you have successfully deployed a highly available and secured WordPress server. Don’t forget to give a thumbs up if you found it helpful, and please remember to terminate AWS resources and services once you have completed your demo.

Happy Cloud Computing!

--

--