Categories AWS DevOps

Introduction to Terraform with AWS Lightsail: Deploying WordPress Infrastructure

Introduction

In today’s cloud-first world, managing infrastructure manually is no longer practical. Terraform, a powerful Infrastructure as Code (IaC) tool, combined with AWS Lightsail, offers a streamlined approach to deploying and managing web applications. This guide focuses on deploying a WordPress infrastructure using Terraform to automate AWS Lightsail resources.

By using Terraform with AWS Lightsail, you’ll benefit from:

  • Consistent, version-controlled infrastructure
  • Automated deployment processes
  • Reduced human error
  • Cost-effective resource management

We’ll build a complete WordPress deployment including multiple instances, a managed MySQL database, and a load balancer for high availability. For more information on AWS Lightsail read Deploying Applications on AWS Lightsail to get started.

Prerequisites

Before beginning this project, ensure you have:

  • An active AWS account with appropriate permissions
  • Terraform (version 0.12 or later) installed on your local machine
  • AWS CLI installed and configured
  • Basic familiarity with WordPress administration
  • Understanding of basic networking concepts

Understanding the Components

AWS Lightsail Overview

AWS Lightsail is Amazon’s simplified cloud platform offering:

Features and Benefits:

  • Pre-configured application stacks
  • Simplified virtual server management
  • Managed databases
  • Integrated load balancers
  • Fixed, predictable pricing
  • Easy scaling options

Available Resources:

  • Virtual Private Servers (instances)
  • Managed databases
  • Load balancers
  • Static IPs
  • DNS management

Project Architecture

Our WordPress deployment consists of:

  • Multiple WordPress instances for redundancy
  • A managed MySQL database for data persistence
  • Load balancer for traffic distribution
  • Networking components for security and access

Setting Up the Development Environment

Installing Required Tools

  1. Terraform Installation:
# macOS (using Homebrew)
brew install terraform

# Linux
curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
sudo apt-get update && sudo apt-get install terraform
  1. AWS CLI Setup:
# macOS
brew install awscli

# Linux
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install

Configuring AWS Credentials

aws configure

Project Directory Structure

wordpress-lightsail/
├── main.tf
├── variables.tf
├── outputs.tf
└── terraform.tfvars

Initial Terraform Configuration

Create a new directory and initialize Terraform:

mkdir wordpress-lightsail
cd wordpress-lightsail
terraform init

Creating the Base Infrastructure

Provider Configuration

provider "aws" {
  region = var.region
}

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

This configuration does two important things:

  1. Sets up the AWS provider using the region specified in our variables
  2. Specifies that we need the AWS provider from HashiCorp’s registry at version 4.x to ensure compatibility with our code and prevent unexpected changes from newer provider versions

Variables and Data Sources

Create variables.tf:

variable "region" {
  description = "AWS region"
  default     = "us-east-1"
}

variable "project_name" {
  description = "Project name for resource naming"
  default     = "wptest"
}

variable "environment" {
  description = "Deployment environment"
  default     = "dev"
}

variable "instance_count" {
  description = "Number of WordPress instances"
  default     = 2
}

variable "db_username" {
  description = "MySQL user name"
  default     = "wordpress"
}

variable "db_password" {
  description = "MySQL password"
  default     = "Really-$ecret-passw0rd!"
}
variable "domain_name" {
  description = "Wordpress Domain"
  default     = "fake-domain.local"
}

These variables define the core configuration values for our infrastructure. The region, project name, and environment variables will be used for resource naming and location. Instance count controls the number of WordPress servers we’ll deploy, while the database variables store credentials (which in production should be handled more securely through a secret management service).

Basic Resource Structure

Follow these naming conventions:

  • Use lowercase with hyphens
  • Include project name in resource names
  • Add purpose-specific suffixes
  • Tag all resources appropriately

Database Deployment

MySQL Database Configuration

resource "aws_lightsail_database" "wordpress_db" {
  relational_database_name = "${var.project_name}-db"
  availability_zone       = "${var.region}a"
  blueprint_id           = "mysql_8_0"
  bundle_id             = "micro_2_0"
  master_database_name  = "wordpress"
  master_username       = var.db_username
  master_password       = var.db_password
  backup_retention_enabled = true
}

This code creates a MySQL 8.0 database instance in the specified availability zone. The micro_2_0 bundle provides enough resources for a small WordPress site while keeping costs down. We enable backup retention to ensure data durability, and configure the database with credentials from our variables.

Security Considerations

Performance Settings

  • Choose appropriate bundle size based on workload
  • Enable automated backups
  • Configure monitoring alerts
  • Set up maintenance windows

WordPress Instance Deployment

Instance Configuration

resource "aws_lightsail_instance" "wordpress" {
  count             = var.instance_count
  name              = "${var.project_name}-instance-${count.index}"
  availability_zone = "${var.region}a"
  blueprint_id      = "wordpress"
  bundle_id         = "small_2_0"

  user_data = <<-EOF
              #!/bin/bash
              # Configure WordPress database connection
              wp_config="/opt/bitnami/wordpress/wp-config.php"
              sed -i "s/define( 'DB_HOST', '.*' );/define( 'DB_HOST', '${aws_lightsail_database.wordpress_db.master_endpoint_address}' );/" $wp_config
              sed -i "s/define( 'DB_NAME', '.*' );/define( 'DB_NAME', 'wordpress' );/" $wp_config
              sed -i "s/define( 'DB_USER', '.*' );/define( 'DB_USER', '${var.db_username}' );/" $wp_config
              sed -i "s/define( 'DB_PASSWORD', '.*' );/define( 'DB_PASSWORD', '${var.db_password}' );/" $wp_config
              EOF
}

This code creates multiple WordPress instances using a count based on our instance_count variable. Each instance uses Lightsail’s WordPress blueprint and includes a startup script that automatically configures the WordPress database connection to use our external MySQL database instead of the default local database.

Static IP Assignment

resource "aws_lightsail_static_ip" "wordpress" {
  count = var.instance_count
  name  = "${var.project_name}-static-ip-${count.index}"
}

resource "aws_lightsail_static_ip_attachment" "wordpress" {
  count          = var.instance_count
  static_ip_name = aws_lightsail_static_ip.wordpress[count.index].name
  instance_name  = aws_lightsail_instance.wordpress[count.index].name
}

Static IPs ensure our WordPress instances maintain the same public IP addresses even after restarts or replacements. The first resource creates static IP addresses, while the second attaches them to our WordPress instances. This prevents downtime due to IP changes when instances are restarted and simplifies DNS configuration if needed.

Load Balancer Setup

Load Balancer Configuration

resource "aws_lightsail_lb" "wordpress" {
  name               = "${var.project_name}-lb"
  health_check_path  = "/"
  instance_port      = 80
  tags = {
    Environment = var.environment
  }
}

resource "aws_lightsail_lb_attachment" "wordpress" {
  count           = var.instance_count
  lb_name         = aws_lightsail_lb.wordpress.name
  instance_name   = aws_lightsail_instance.wordpress[count.index].name
}

The load balancer distributes traffic across multiple WordPress instances for improved reliability and performance. The first resource creates the load balancer that checks instance health by accessing the root path (“/”) and forwards traffic to port 80. The second resource attaches each WordPress instance to the load balancer, ensuring traffic is distributed across all available instances, improving both reliability and performance.

SSL/TLS Setup

resource "aws_lightsail_lb_certificate" "wordpress" {
  name             = "${var.project_name}-cert"
  lb_name          = aws_lightsail_lb.wordpress.name
  domain_name      = var.domain_name
}

This code provisions an SSL/TLS certificate for secure HTTPS connections to your WordPress site. The certificate is automatically attached to the load balancer and will be used for encrypted connections to your domain.

Networking and Security

Firewall Rules

resource "aws_lightsail_instance_public_ports" "wordpress" {
  count         = var.instance_count
  instance_name = aws_lightsail_instance.wordpress[count.index].name

  port_info {
    protocol  = "tcp"
    from_port = 80
    to_port   = 80
  }

  port_info {
    protocol  = "tcp"
    from_port = 443
    to_port   = 443
  }
}

This configuration opens HTTP (port 80) and HTTPS (port 443) access to our WordPress instances, allowing web traffic while keeping other ports closed for security. By explicitly defining only the necessary ports, we reduce the attack surface and improve the overall security posture of our infrastructure.

Domain Setup

resource "aws_lightsail_domain" "wordpress" {
  domain_name = var.domain_name
}

resource "aws_lightsail_domain_entry" "wordpress" {
  domain_name = aws_lightsail_domain.wordpress.domain_name
  type        = "CNAME" 
  name        = "www"
  target      = aws_lightsail_lb.wordpress.dns_name
}

Configure DNS settings to make the WordPress site accessible via your domain name. The first resource registers your domain with Lightsail’s DNS service. The second creates a CNAME record that points “www.yourdomain.com” to your load balancer, allowing users to access your WordPress site using the www subdomain.

Deployment Process

Terraform Workflow

  1. Initialize the working directory:
terraform init
  1. Review the execution plan:
terraform plan
  1. Apply the configuration:
terraform apply

Validation Steps

  • Verify WordPress accessibility
  • Test database connectivity
  • Confirm load balancer distribution
  • Check SSL certificate validity
  • Validate domain resolution

Maintenance and Operations

Monitoring Setup

  • Enable Lightsail monitoring
  • Configure CloudWatch alerts
  • Set up performance metrics
  • Monitor resource utilization

Backup Strategies

  • Enable automated database backups
  • Configure instance snapshots
  • Implement disaster recovery plan
  • Test restore procedures regularly

Update Procedures

  1. Create instance snapshots
  2. Apply WordPress updates
  3. Update database versions
  4. Rotate SSL certificates
  5. Review security patches

Best Practices and Optimization

Security Recommendations

  • Use strong passwords
  • Implement least privilege access
  • Enable HTTPS only
  • Regular security audits
  • Keep WordPress core and plugins updated

Cost Optimization

  • Right-size instances
  • Monitor resource usage
  • Clean up unused resources
  • Use fixed-price bundles
  • Enable cost alerts

Conclusion

This guide has demonstrated how to deploy a scalable WordPress infrastructure using Terraform and AWS Lightsail. By following these practices, you can create a reliable, maintainable, and cost-effective WordPress deployment.

Next Steps

  • Implement monitoring and alerting
  • Set up continuous deployment
  • Configure backup automation
  • Implement security hardening

Appendix

Command Cheatsheet

# Initialize Terraform
terraform init

# Format configuration
terraform fmt

# Validate configuration
terraform validate

# Plan deployment
terraform plan

# Apply changes
terraform apply

# Destroy resources terraform destroy

You May Also Like