Infrastructure as Code for Web Fleets: Automating WordPress Deployments at Scale

Infrastructure as Code for Web Fleets: Automating WordPress Deployments at Scale

What Is Infrastructure as Code?

Infrastructure as Code (IaC) is a software engineering practice that treats infrastructure configuration—servers, databases, networks, security groups—as versioned, testable code rather than manual, ad-hoc configurations. Instead of clicking through cloud provider consoles or running shell scripts by hand, teams define infrastructure using declarative or imperative languages, then commit that code to version control alongside application source.

For WordPress fleet operators managing dozens or hundreds of sites across regions, IaC is transformative. It replaces brittle manual processes with reproducible, auditable infrastructure definitions that scale consistently from one server to one thousand.

The Core Business Case: Why WordPress Fleets Need IaC

Vilee LLC operates 520+ online businesses globally across the US, EU, and Southeast Asia. Each business runs on WordPress infrastructure—web servers, databases, CDNs, backup systems. Without IaC:

  • Configuration drift: One server gets a security patch; another doesn’t. Environment inconsistency cascades into production bugs.
  • Slow scaling: Adding 50 new WordPress instances means 50 manual provisioning steps, each prone to typos or missed steps.
  • Risky updates: Upgrading PHP or applying security patches manually across a fleet risks broken deployments and data loss.
  • No audit trail: Who changed what, when? Manual changes leave no record.
  • Disaster recovery nightmare: If infrastructure burns down, rebuilding from memory or incomplete documentation wastes hours.

IaC solves these problems by making infrastructure definition explicit, version-controlled, and repeatable.

Core Benefits of Infrastructure as Code

Reproducibility

Run the same IaC configuration against any cloud provider (AWS, Google Cloud, Azure) and you get identical infrastructure. With Terraform, developers can provision identical environments with a single command, reducing human error and ensuring infrastructure uniformity. This means staging matches production exactly; dev environments mirror live behavior.

Version Control & Auditability

Infrastructure code lives in Git. Every change is tracked: who changed it, when, why (via commit messages), and it can be reviewed before merging. For compliance-heavy WordPress fleets handling e-commerce or sensitive data, this audit trail is essential. Rollback to a previous known-good infrastructure state with a single Git command.

Consistency Across Fleets

A single module definition applied to 500 WordPress servers guarantees they’re configured identically. Security hardening, PHP versions, Nginx optimization, database backups—all consistent. Commands executed via Ansible are idempotent, meaning they can be applied multiple times and will always result in the same outcome.

Fast Provisioning

Spinning up new WordPress infrastructure takes minutes instead of hours. Terraform can provision 10 EC2 instances, RDS database, security groups, load balancer, DNS records in parallel. For e-commerce fleets handling seasonal traffic spikes, this agility is a competitive advantage.

Fewer Configuration Drift Errors

Configuration drift—where actual infrastructure diverges from intended state—is a silent killer. One server missing a security patch; another running an outdated PHP version. IaC drift occurs when infrastructure resources differ from the configuration defined in code, invalidating the code as the single source of truth. Idempotent tools prevent drift by detecting and correcting deviations automatically.

Declarative vs. Imperative: Terraform vs. Ansible

Two dominant philosophies exist in IaC, each suited to different infrastructure tasks.

Declarative: Terraform

Terraform uses declarative configuration where you define the desired end state, and Terraform’s engine automatically determines the steps necessary to reach that state. Write once: “I want 5 EC2 instances, a load balancer, an RDS database in a VPC with specific security rules.” Terraform makes it so.

Strengths:

Weakness: Less suited to sequential, step-by-step operational tasks like “upgrade PHP, then validate, then rollback on failure.”

Imperative: Ansible

Ansible takes a procedural approach where you define step-by-step instructions on how to achieve the desired result. Write playbooks: “Install Nginx, configure PHP-FPM, harden SSH, restart services.” Ansible executes in order.

Strengths:

  • Agent-less: SSH to servers, no additional software to install.
  • Excellent for day-1 configuration (post-provisioning software setup) and day-2 operations (patches, updates, ongoing management).
  • Naturally idempotent: run playbooks repeatedly; unchanged servers skip unchanged tasks.
  • Human-readable YAML syntax; lower learning curve than HCL.
  • Can manage mutable infrastructure—patch servers in place rather than replacing them.

Weakness: No built-in state file; harder to track what’s deployed across large fleets.

Best Practice: Use Both

The most effective modern automation strategies use Terraform and Ansible together to achieve comprehensive infrastructure lifecycle management: Terraform for day 0 provisioning and Ansible for day 1 configuration and day 2 operations. Terraform provisions AWS resources; Ansible configures WordPress on those resources.

Managing Multiple WordPress Servers as Code

Consider Vilee’s real-world scenario: 520+ WordPress sites spread across regions. Three representative sites: US-based SaaS platform, EU e-commerce store, Southeast Asia marketplace.

Layer 1: Provision with Terraform

Define infrastructure in HCL:

# Terraform: variables.tf, main.tf
variable "site_count" { default = 3 }
variable "region" { type = string }

resource "aws_instance" "wordpress_server" {
  count = var.site_count
  instance_type = "t3.medium"
  ami = data.aws_ami.ubuntu_22.id
  tags = { Name = "wordpress-${count.index}" }
}

resource "aws_rds_instance" "wordpress_db" {
  count = var.site_count
  allocated_storage = 20
  engine = "mysql"
  instance_class = "db.t3.micro"
}

resource "aws_lb" "wordpress_alb" {
  name = "wp-alb"
  internal = false
}

Run terraform apply: instantly, AWS spins up 3 EC2 instances, 3 RDS databases, load balancer, security groups. Terraform stores state; future runs update only changed resources.

Layer 2: Configure with Ansible

Ansible is built for managing large server fleets; define the desired state once, and Ansible enforces it across every server in the fleet. Create an inventory of the 520 WordPress servers, then apply a playbook:

# Ansible: playbook.yml
---
- hosts: wordpress_servers
  become: yes
  tasks:
    - name: Install LEMP stack
      apt:
        name: ["nginx", "php-fpm", "php-mysql", "mysql-client"]
        state: present
    
    - name: Configure PHP
      template:
        src: php.ini.j2
        dest: /etc/php/8.2/fpm/php.ini
        backup: yes
    
    - name: Download WordPress
      command: wp core download --allow-root
      args:
        chdir: /var/www/html
    
    - name: Configure WordPress
      command: wp config create --allow-root
      args:
        chdir: /var/www/html
    
    - name: Restart Nginx
      systemd:
        name: nginx
        state: restarted

Run ansible-playbook playbook.yml -i inventory.ini: all 520 servers configure in parallel (or in rolling batches). Change PHP version? Update the template, re-run playbook. Idempotency ensures servers already on that version skip that task.

Secrets Management in Infrastructure as Code

IaC code is version-controlled and shared. Database passwords, API keys, SSL certificates must never be hardcoded in code.

Best Practices

Secrets must not be stored in infrastructure code, and an appropriate secrets management tool such as Vault, AWS Secrets Manager or Kubernetes secrets must be used.

What NOT to Do

  • Never commit plaintext secrets to Git (even private repos).
  • Never hardcode credentials in Terraform .tfvars or Ansible group_vars.
  • Never store credentials in Docker image layers.
  • Don’t skip secret rotation—it’s automated if you set it up.

State Management & Terraform State Files

Terraform maintains a state file (terraform.tfstate) recording what’s deployed: EC2 instance IDs, RDS endpoints, security group rules. This state is the source of truth.

State Storage Best Practices

Configure IaC tools to use a remote backend like AWS S3 with DynamoDB for locking or Terraform Cloud, which centralizes state, enables team collaboration, and prevents dangerous race conditions.

Modules & Reusable Infrastructure Code

Writing Terraform from scratch for each site is tedious. Modules package reusable infrastructure building blocks.

Example: WordPress Module

Terraform modules should be designed to be reusable and maintainable by being well-documented, versioned, and tested, ensuring they can easily be shared and reused across projects.

# terraform/modules/wordpress-site/main.tf
resource "aws_instance" "web" {
  ami = var.ami_id
  instance_type = var.instance_type
  tags = { Name = var.site_name }
}

resource "aws_rds_instance" "db" {
  allocated_storage = var.db_storage
  engine = "mysql"
  instance_class = var.db_instance_type
  db_name = var.db_name
  username = var.db_user
  password = var.db_password  # from Secrets Manager
}

resource "aws_security_group" "web" {
  ingress { from_port = 80; to_port = 80; protocol = "tcp" }
  ingress { from_port = 443; to_port = 443; protocol = "tcp" }
  egress { from_port = 0; to_port = 0; protocol = "-1" }
}

Then use the module for each site:

# terraform/prod/main.tf
module "us_saas" {
  source = "../modules/wordpress-site"
  site_name = "us-saas"
  instance_type = "t3.medium"
  db_name = "wp_us_saas"
}

module "eu_ecommerce" {
  source = "../modules/wordpress-site"
  site_name = "eu-ecommerce"
  instance_type = "t3.large"
  db_name = "wp_eu_ecom"
}

module "apac_marketplace" {
  source = "../modules/wordpress-site"
  site_name = "apac-marketplace"
  instance_type = "t3.xlarge"
  db_name = "wp_apac_market"
}

Define once, reuse everywhere. Update the module (e.g., upgrade PHP version); all sites using it get the update with terraform apply.

Vilee LLC combines deep technical expertise in WordPress/WooCommerce development with AI-powered automation to operate 520+ profitable online businesses at scale.

Continuous Integration for Infrastructure

Treat infrastructure code like application code: test before deploying.

IaC Testing Pipeline

A WordPress CI/CD pipeline automates code testing, integration, and deployment processes to reduce manual errors and accelerate release cycles.

  • Syntax Validation: terraform validate checks HCL syntax before apply.
  • Policy as Code: Tools like Sentinel (Terraform Cloud) enforce organizational policies (e.g., all RDS instances must be encrypted, all security groups must restrict SSH to VPN).
  • Cost Estimation: terraform plan shows resource costs before apply; catch budget overruns early.
  • Security Scanning: GitHub Actions can trigger automated testing and validation of infrastructure changes before deployment.
  • Staged Rollout: Merge Terraform to dev branch → CI validates and applies to dev environment → code review approved → merge to prod → CI applies to production.

Example GitHub Actions workflow:

# .github/workflows/terraform.yml
name: Terraform
on: [push, pull_request]
jobs:
  terraform:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: hashicorp/setup-terraform@v1
      - run: terraform init
      - run: terraform validate
      - run: terraform plan -out=tfplan
      - run: terraform apply tfplan

Idempotency: The IaC Superpower

A properly idempotent system can be run repeatedly without side effects. Run the same Ansible playbook 10 times; servers already in the desired state skip unchanged tasks.

Idempotence is a principle where operations can be applied multiple times without changing results; running an IaC script repeatedly will always result in the same defined state.

Benefits:

  • Recover from partial failures: playbook crashes mid-run? Re-run it; it picks up where it left off.
  • Schedule maintenance safely: upgrade PHP on a 500-server fleet, re-run playbook each hour to catch drifted servers.
  • On-board new engineers: run the full provisioning playbook for their dev environment; it’s idempotent, so running twice doesn’t break anything.
  • Reduce support tickets: instead of manual fixes, “run this playbook” is the answer to 80% of operational issues.

IaC Configuration Drift & Detection

Even with IaC, drift happens: manual SSH changes, failed updates, cloud provider patches. Catch and prevent it.

Drift Detection

  • Terraform Refresh: terraform refresh queries actual AWS state, updates local state file to match reality. terraform plan then shows drift.
  • Ansible Dry-Run: ansible-playbook playbook.yml --check simulates applying the playbook without actually changing anything; see what would change.
  • Regular Audits: Daily/weekly Terraform plan or Ansible check runs catch drift. Trigger alerts on detected drift.
  • Immutable Infrastructure: Replace servers rather than patch. Drift is moot if servers live 30 days and are replaced, not modified in place.

Implementation Checklist for WordPress Fleets

Phase Task Owner Timeline
Week 1 Set up Terraform and Ansible repos; version control DevOps Lead 2–3 days
Week 1 Design VPC, subnets, security groups in Terraform Cloud Architect 2–3 days
Week 2 Build EC2 + RDS Terraform modules; test locally with Terraform Cloud DevOps Engineer 3–5 days
Week 2–3 Create Ansible playbooks for WordPress stack (Nginx, PHP, WP-CLI) Systems Engineer 5–7 days
Week 3 Set up secrets (AWS Secrets Manager + IAM roles) Security Engineer 2–3 days
Week 3–4 Build CI/CD pipeline (GitHub Actions or GitLab CI) DevOps Engineer 3–4 days
Week 4 Test on staging: provision 5 sites, verify WordPress works QA / DevOps 2–3 days
Week 5 Roll out to production; migrate 50 WordPress sites DevOps Lead + Team 5–7 days
Week 6+ Monitor drift, optimize, scale to full fleet On-call Engineer Ongoing

Common Gotchas & How to Avoid Them

  • Terraform state in Git: Never commit terraform.tfstate. Use remote backend (S3 + DynamoDB) from day one.
  • Secrets in code: Use AWS Secrets Manager, Vault, or encrypted Ansible Vault files. Never plaintext.
  • Idempotency failures: Some tasks (e.g., ansible shell) are not idempotent by default. Use idempotent modules (file, copy, template) or add register/when conditionals.
  • Forgetting state locking: Two engineers run terraform apply simultaneously; state file corrupts. Enable DynamoDB locking or Terraform Cloud.
  • Over-coupling modules: Avoid deeply nested module dependencies. Keep modules simple, focused, independent.
  • Inadequate testing: Test Terraform + Ansible changes in a staging environment first. Use terraform plan and ansible --check.

Why Vilee Chooses Infrastructure as Code

Operating 520+ WordPress sites globally demands automation. Manual provisioning doesn’t scale. IaC enables:

  • Speed: Launch new sites in minutes, not hours.
  • Consistency: Every site is configured identically, reducing support burden.
  • Reliability: Automated deployments with built-in tests catch errors before production.
  • Cost Control: Terraform plan shows costs before apply; scale down unused infrastructure instantly.
  • Team Scaling: New engineers onboard by reading Terraform code + Ansible playbooks, not tribal knowledge or runbooks.
  • Compliance: Version control provides audit trails; secrets encrypted and rotated automatically.

Next Steps: Getting Started

  1. Read: Familiarize yourself with Terraform HCL syntax and Ansible YAML playbooks. Set up Docker for WordPress development locally to test IaC changes risk-free.
  2. Start Small: Write Terraform to provision a single EC2 + RDS database. Use Ansible to install WordPress on it. Iterate.
  3. Version Control: Commit infrastructure code to Git. Use branches for features (e.g., feature/php-8.3-upgrade). Require code review before merging.
  4. Automate Testing: Build a CI/CD pipeline that validates and tests IaC changes on every commit.
  5. Scale: Once single-site workflow is solid, package it into modules and replicate across 100, 500, 1000 sites.
  6. Monitor: Implement drift detection. Schedule regular Terraform plan / Ansible check runs to catch deviations.

For teams managing WordPress at scale, IaC is not optional—it’s the foundation of reliable, fast, cost-effective operations. Contact Vilee to discuss how Infrastructure as Code can transform your WordPress fleet.

FAQs

Can I use Terraform and Ansible together for WordPress?

Yes, and it’s best practice. Terraform handles day 0 provisioning (creating infrastructure) while Ansible handles day 1 configuration and day 2 operations (software deployment, updates, ongoing management). Terraform creates the servers; Ansible installs WordPress on them. This division of labor is powerful.

How do I handle secrets in Terraform and Ansible?

Never hardcode secrets. Use AWS Secrets Manager (Terraform can reference it), HashiCorp Vault, or Ansible Vault. Configure automated credential rotation to limit the window of opportunity for attackers if a credential is compromised. Grant access via IAM roles, not shared credentials.

What if my infrastructure drifts from code?

Use terraform refresh to sync state with reality, then terraform plan to see drift. For Ansible, run ansible-playbook --check to see what would change. Implement automated drift detection (daily Terraform plan runs, monitoring alerts on changes). Consider immutable infrastructure: replace drifted servers rather than patching them.

Frequently Asked Questions

Can I use Terraform and Ansible together for WordPress?

Yes, and it’s best practice. Terraform handles day 0 provisioning (creating infrastructure) while Ansible handles day 1 configuration and day 2 operations (software deployment, updates, ongoing management). Terraform creates the servers; Ansible installs WordPress on them. This division of labor is powerful.

How do I handle secrets in Terraform and Ansible?

Never hardcode secrets. Use AWS Secrets Manager (Terraform can reference it), HashiCorp Vault, or Ansible Vault. Configure automated credential rotation to limit the window of opportunity for attackers if a credential is compromised. Grant access via IAM roles, not shared credentials.

What if my infrastructure drifts from code?

Use terraform refresh to sync state with reality, then terraform plan to see drift. For Ansible, run ansible-playbook –check to see what would change. Implement automated drift detection (daily Terraform plan runs, monitoring alerts on changes). Consider immutable infrastructure: replace drifted servers rather than patching them.

Talk to us →