Diagram for WordPress with Maria DB RDS as deployed by Terraform

Created a WordPress Website with a Relational Database from Terraform

I received a request from management to create a base wordpress website instance on Terraform for easy future deployments including room for additional services like Elasticache, ASG groups, and other resources.

WordPress is a very dynamic content management system that is mostly deployed on a LAMP stack. For this project instead of deploying the application with MySQL, I used MariaDB which is an enhanced open source fork of MySQL. I used MariaDB simply because of its speed, security, and scalability which will more than compliment any future WordPress website project. The WordPress instance is behind an application load balancer for environment efficiency and scalability.

The Terraform template will deploy with bootstrapped userdata to create the LAMP stack with AWS Linux 2, PHP, Apache, MariaDB, WordPress, database configurations, and AWS Linux extras.

code

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 4.0"
    }
  }
}

# Define the provider
provider "aws" {
  region = "us-east-1"
}

# Define VPC
resource "aws_vpc" "prod-vpc" {
  cidr_block = "192.168.0.0/16"
  enable_dns_hostnames = true
  tags = {
    Name = "main-vpc"
  }
}

# Creating Public subnet!
resource "aws_subnet" "subnet1" {
  vpc_id            = aws_vpc.prod-vpc.id
  cidr_block        = "192.168.0.0/24"
  availability_zone = "us-east-1a"
  map_public_ip_on_launch = true
  tags = {
    Name = "Public Subnet1"
  }
}

# Creating Private subnet!
resource "aws_subnet" "subnet2" {
  vpc_id            = aws_vpc.prod-vpc.id
  cidr_block        = "192.168.1.0/24"
  availability_zone = "us-east-1b"
  tags = {
    Name = "Private Subnet1"
  }
}

# Creating 2nd Private subnet!
resource "aws_subnet" "subnet3" {
  vpc_id            = aws_vpc.prod-vpc.id
  cidr_block        = "192.168.2.0/24"
  availability_zone = "us-east-1c"
  tags = {
    Name = "Private Subnet2"
  }
}

resource "aws_db_subnet_group" "private" {
  name       = "main"
  subnet_ids = [aws_subnet.subnet2.id, aws_subnet.subnet3.id]

  tags = {
    Name = "My DB subnet group"
  }
}

# Creating an Internet Gateway for the VPC
resource "aws_internet_gateway" "Internet_Gateway" {
  vpc_id = aws_vpc.prod-vpc.id

  tags = {
    Name = "IG-Public-&-Private-VPC"
  }
}

# Creating an Route Table for the public subnet!
resource "aws_route_table" "Public-Subnet-RT" {
  vpc_id = aws_vpc.prod-vpc.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.Internet_Gateway.id
  }

  tags = {
    Name = "Route Table for Internet Gateway"
  }
}

# Creating a resource for the Route Table Association!
resource "aws_route_table_association" "RT-IG-Association" {
  subnet_id       = aws_subnet.subnet1.id
  route_table_id  = aws_route_table.Public-Subnet-RT.id
}

# Define the security group for the WordPress EC2 instance
resource "aws_security_group" "wordpress_sg" {
  name_prefix = "wordpress-sg-"

  vpc_id = aws_vpc.prod-vpc.id

  # Inbound traffic
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = 3306
    to_port     = 3306
    protocol    = "tcp"
    security_groups = [aws_security_group.mariadb_sg.id]
  }

  # Outbound traffic
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

# Define the security group for the MariaDB RDS instance
resource "aws_security_group" "mariadb_sg" {
  name_prefix = "mariadb-sg-"

  vpc_id = aws_vpc.prod-vpc.id

  # Inbound traffic
  ingress {
    from_port   = 3306
    to_port     = 3306
    protocol    = "tcp"
    security_groups = [aws_security_group.wordpress_sg.id]
  }

  # Outbound traffic
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

# Define the EC2 instance for WordPress
resource "aws_instance" "wordpress" {
  ami           = "ami-xxxxxxxxxxxxxxx" # Replace with the desired AMI ID with AWS Linux 2 for LAMP stack
  instance_type = "t2.micro"            # The instance type to use, e.g., t2.micro

  subnet_id     = aws_subnet.subnet1.id  # Place the EC2 instance in the public subnet

  # Associate the security group with the EC2 instance
  vpc_security_group_ids = [aws_security_group.wordpress_sg.id]

  user_data = data.template_cloudinit_config.user_data.rendered

  tags = {
    Name = "WordPress-Instance"
  }
}
# Define the RDS instance
resource "aws_db_instance" "wordpressdb" {
  allocated_storage      = 20
  engine                 = "mysql"
  engine_version         = "5.7"
  instance_class         = "db.t2.micro"
  db_name                = "mydb"
  username               = "myuser"
  password               = "mypassword"
  db_subnet_group_name   = aws_db_subnet_group.private.id
  vpc_security_group_ids = [aws_security_group.mariadb_sg.id]

  tags = {
    Name = "MySQL"
  }
}
# Define the Application Load Balancer
resource "aws_lb" "wordpress_alb" {
  name               = "wordpress-alb"
  internal           = false
  load_balancer_type = "application"

  subnets         = [aws_subnet.subnet1.id, aws_subnet.subnet2.id, aws_subnet.subnet3.id]
  security_groups = [aws_security_group.wordpress_sg.id]

  tags = {
    Name = "wordpress-alb"
  }
}

# Define the ALB Target Group for the EC2 instances
resource "aws_lb_target_group" "wordpress_target_group" {
  name     = "wordpress-target-group"
  port     = 80
  protocol = "HTTP"
  vpc_id   = aws_vpc.prod-vpc.id

  health_check {
    path                = "/"
    protocol            = "HTTP"
    interval            = 30
    timeout             = 5
    healthy_threshold   = 2
    unhealthy_threshold = 2
  }
}

# Associate the EC2 instances with the ALB Target Group
resource "aws_lb_target_group_attachment" "wordpress_target_attachment" {
  target_group_arn = aws_lb_target_group.wordpress_target_group.arn
  target_id        = aws_instance.wordpress.id
  port             = 80
}

# Define the ALB Listener to forward traffic to the Target Group
resource "aws_lb_listener" "wordpress_listener" {
  load_balancer_arn = aws_lb.wordpress_alb.arn
  port              = "80"
  protocol          = "HTTP"

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.wordpress_target_group.arn
  }
}

# Variables section
variable "database_user" {
  description = "Username for the WordPress database"
  default     = "myuser"
}

variable "database_password" {
  description = "Password for the WordPress database"
  default     = "mypassword"
}

variable "database_name" {
  description = "Name of the WordPress database"
  default     = "mydb"
}

# Combine Terraform template and userdata script
data "template_cloudinit_config" "user_data" {
  gzip          = true
  base64_encode = true

  part {
    content_type = "text/x-shellscript"
    content      = <<-EOF
      #!/bin/bash
      db_username=${var.database_user}
      db_user_password=${var.database_password}
      db_name=${var.database_name}
      db_RDS=${aws_db_instance.wordpressdb.endpoint}

      # Install LAMP Server
      yum update -y
      yum install -y httpd
      yum install -y mysql

      # Enable PHP 7.xx from Amazon Linux Extra and install it
      amazon-linux-extras enable php7.4
      yum clean metadata
      yum install -y php php-{pear,cgi,common,curl,mbstring,gd,mysqlnd,gettext,bcmath,json,xml,fpm,intl,zip,imap,devel}

      # Install Imagick extension
      yum -y install gcc ImageMagick ImageMagick-devel ImageMagick-perl
      pecl install imagick
      chmod 755 /usr/lib64/php/modules/imagick.so
      cat <>/etc/php.d/20-imagick.ini

      extension=imagick

      EOI

      systemctl restart php-fpm.service
      systemctl start  httpd

      # Change OWNER and permission of directory /var/www
      usermod -a -G apache ec2-user
      chown -R ec2-user:apache /var/www
      find /var/www -type d -exec chmod 2775 {} \;
      find /var/www -type f -exec chmod 0664 {} \;

      yum -y install mariadb-server
      service mariadb start

      # Install WordPress using WP CLI
      curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
      chmod +x wp-cli.phar
      mv wp-cli.phar /usr/local/bin/wp
      wp core download --path=/var/www/html --allow-root
      wp config create --dbname=$db_name --dbuser=$db_username --dbpass=$db_user_password --dbhost=$db_RDS --path=/var/www/html --allow-root --extra-php </,/<\/Directory>/ s/AllowOverride None/AllowOverride all/' /etc/httpd/conf/httpd.conf

      # Make Apache autostart and restart Apache
      systemctl enable httpd.service
      systemctl restart httpd.service

      echo "WordPress Installed"
    EOF
  }
}

Ralph Quick Cloud Engineer

Ralph Quick is a professional Cloud Engineer specializing in the management, maintenance, and deployment of web service applications and infrastructure for operations. His experience ensures services are running efficiently and securely meeting the needs of your organization or clients.

Ready to Chat?

Let’s Socialize!

+1 (754) 214-7728

    10 + 15 =

    Share This