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.