Creating the Blog site

I deployed a WordPress blog site on AWS within a VPC spanning five subnets across two Availability Zones:

  • Public subnets for a NAT instance, Bastion Host, and Application Load Balancer (ALB).
  • Private subnets for the web server and Amazon RDS (MySQL).

Traffic is managed through an ALB, with Route 53 handling DNS and an ACM SSL certificate securing connections. Security groups enforce strict access controls, and all necessary software (Apache, PHP, WordPress) is installed on the webserver. The site is now live and accessible via its domain.

Installing SSM Agent

To improve access management, I created an EC2SSMRole with the AmazonSSMManagedInstanceCore IAM policy attached. I also installed the SSM Agent on each server, enabling AWS Systems Manager Session Manager for direct access—eliminating the need for the Bastion Host.

Configuring Security Groups

Each component received appropriate security group rules:

  • Bastion Host: SSH (Port 22) from trusted IPs
  • NAT Instance: Allow outbound traffic for instances in private subnets
  • Web Server: Allow HTTP(S) traffic only from ALB
  • RDS: Allow MySQL traffic only from the web server

Setting Up Private Route Table

To route traffic from private instances to the internet via the NAT instance, I updated the private route table to forward all internet-bound traffic through the NAT instance.

Disabling Source/Destination Check on NAT Instance

For the NAT instance to function properly, I disabled Source/Destination Check on it.

Configuring NAT Instance

To enable NAT functionality, I executed the following commands on the NAT instance:

To make the rule persistent:

Setting Up RDS for WordPress

When I configured an RDS instance for WordPress with MySQL, I chose a single Availability Zone (AZ) deployment for cost reasons. Despite using just one AZ, I still had to create a DB subnet group with two subnets, as this is a requirement for RDS. I placed these subnets in different AZs and ensured they were both private to keep the database instance secure and isolated from the public internet. The creation of the RDS instance provided me with an endpoint that I could use later within my wp-config.php file.

When I set up the RDS instance for WordPress with MySQL, I also created two secrets in AWS Secrets Manager for added security. The first secret stored the RDS endpoint, and the second contained the RDS username and password. By using Secrets Manager, I ensured that sensitive credentials were securely managed and not hardcoded in the wp-config.php file.

Installing and Configuring WordPress

On the webserver, I installed the necessary packages:

Next, I installed WordPress:

I configured database secrets retrieval using AWS Secrets Manager by creating a secrets.php file in the home directory. Using the AWS SDK for PHP, the script securely fetched the MySQL credentials and RDS endpoint stored in Secrets Manager.

Then, I updated wp-config.php with the database credentials and endpoint retrieved from Secrets Manager – see code snippet below.

To ensure secure and cost-effective access to AWS Secrets Manager without routing traffic over the internet, I created a VPC Endpoint for Secrets Manager within my VPC. This allowed my web server to communicate with Secrets Manager using private IPs instead of public AWS endpoints. Additionally, I created a dedicated security group for the VPC Endpoint, allowing inbound traffic only from the web server’s security group. This setup restricted access to only necessary resources, eliminating unnecessary data transfer costs over the internet.

Configuring Route 53 and SSL with ALB

To enhance security and improve availability:

  1. I registered a Route 53 domain.
  2. Requested an ACM certificate for SSL encryption.
  3. Created an Application Load Balancer (ALB) with the SSL certificate.
  4. Updated Route 53 DNS records to point to the ALB.
  5. Configured Target Groups and Listeners to redirect HTTP traffic to HTTPS.

Fixing Redirect Issues

I encountered an issue where my website wasn’t loading due to redirection errors. Adding the following lines in wp-config.php resolved it:

Final Architecture

My site is now live on the domain!