Skip to content

Deploy one or more highly available/load-balanced WordPress websites on DigitalOcean, with a dedicated MySQL cluster via Terraform and Ansible

License

Notifications You must be signed in to change notification settings

Spofibo/terraform-digitalocean-ha-wordpress

Repository files navigation

Highly available WordPress sites on DigitalOcean with Terraform and Ansible

This repository contains Terraform and Ansible configurations to launch and configure the infrastructure on DigitalOcean, and will create the following infrastructure using Terraform:

  • One private VPC
  • Two 1 GB Droplets in the FRA1 datacenter running Ubuntu 21.10
  • One managed MySQL cluster with two DBs and two users
  • One DigitalOcean Load Balancer to route HTTPS traffic to the Droplets
  • One DigitalOcean Cloud Firewall to lock down communication between the Droplets and the outside world

We will then use Ansible to run the following tasks on both Droplets:

  • Update all packages
  • Install the DigitalOcean monitoring agent, to enable resource usage graphs in the Control Panel
  • Install the Nginx web server software
  • Install a demo index.html that shows Sammy and the Droplet's hostname

Prerequisites

When you have the software, an SSH key, and an API token, proceed to the first step.

Step 1 — Clone the Repository and Configure

First, download the repository to your local computer using git clone, and enter the directory:

$ git clone https://github.com/Spofibo/terraform-do-ha-wordpress.git
$ cd terraform-do-ha-wordpress

We need to update a few variables to let Terraform know about our keys and tokens. Terraform will look for variables in any .tfvars file. An example file is included in the repo.

Then, copy the example file to to a new file, removing the .example extension:

$ cp terraform.tfvars.example terraform.tfvars

Open the new file in your favorite text editor, and update the content of the variables with your parameters:

do_token = ""
ssh_fingerprint = ""

Fill in each variable:

  • do_token: is your personal access token for the DigitalOcean API

  • ssh_fingerprint: the DigitalOcean API refers to SSH keys using their fingerprint, which is a shorthand identifier based on the key itself.

    To get the fingerprint for your key, run the following command, being sure to update the path (currently ~/.ssh/id_rsa.pub) to the key you're using with DigitalOcean, if necessary:

    $ ssh-keygen -E md5 -lf ~/.ssh/id_rsa.pub | awk '{print $2}'
    

    The output will be similar to this:

    MD5:ac:eb:de:c1:95:18:6f:d5:58:55:05:9c:51:d0:e8:e3
    

    Copy everything except the initial MD5: and paste it into the variable.

Now we can initialize Terraform. This will download some information for the DigitalOcean Terraform provider, and check our configuration for errors.

$ terraform init

You should get some output about initializing plugins. Now we're ready to provision the infrastructure and configure it.

Step 2 — Run Terraform and Ansible

We can provision the infrastructure with the following command:

$ terraform apply

Terraform will figure out the current state of your infrastructure, and what changes it needs to make to satisfy the configuration in terraform.tf. In this case, it should show that it's creating two Droplets, a load balancer, a firewall, and a null_resource (this is used to create the inventory file for Ansible).

If all looks well, type yes to proceed.

Terraform will give frequent status updates as it launches infrastructure. Eventually, it will complete and you'll be returned to your command line prompt. Take note of the IP that Terraform outputs at the end:

Apply complete! Resources: 5 added, 0 changed, 0 destroyed.

Outputs:

wordpress_lb_ip = 203.0.113.11

This is the IP of your new load balancer. If you navigate to it in your browser, you'll get an error: the Droplets aren't serving anything yet!

Let's fix that by running Ansible to finish setting up the servers:

$ cd ansible/
$ ansible-galaxy install -r requirements.yaml
$ ansible-playbook -i inventory playbook.yaml

Ansible will output some status information as it works through the tasks we've defined in ansible.yml. When it's done, the two Droplets will both be serving a unique web page that shows the hostname of the server.

Go back to your browser and enter the load balancer IP again. It may take a few moments to start working, as the load balancer needs to run some health checks before putting the Droplets back into its round-robin rotation. After a minute or so the demo web page with Sammy the shark will load:

Demo web page with Sammy the shark and a hostname

If you refresh the page, you'll see the hostname toggle back and forth as the load balancer distributes the requests between both backend servers (some browsers cache more heavily than others, so you may have to hold SHIFT while refreshing to actually send a new request to the load balancer).

Take some time to browse around the DigitalOcean Control Panel to see what you've set up. Notice the two Droplets, demo-01 and demo-02 in your Droplets listing. Navigate to the Networking section and take a look at the demo-lb load balancer:

DigitalOcean load balancer interface

In the Firewalls tab, you can investigate the demo-firewall entry. Notice how the Droplets are set up to only accept web traffic from the load balancer:

DigitalOcean firewall rules interface

When you're done exploring, you can destroy all of the demo infrastructure using Terraform:

$ terraform destroy

This will delete everything we've setup. Or, you could build upon this configuration to deploy your own web site or application! Read on for suggestions of further resources that might help.

TODO

  • Move this list to GH issues
  • README
    • Refine docs
    • Add architecture diagram
  • Terraform
    • Combine with Packer to build hardened images ans use them as base
  • Ansible
    • Cron for cloudflare script
    • Valid self-signed ssl cert for Nginx
    • NFS for wp-content to be shared between droplets
      • How to address scaling up and down, in regards to the registration/deregistration of nodes?
    • Install & use wp-cli to install sites
    • Move sections from playbook to their individual roles
    • Simplify PHP configuration by removing external dependency or disabling some parts of it (i.e. apache stuff)
    • Create different linux user for each website
  • CI/CD (GH Actions) ?

Requirements

Name Version
terraform >= 1.0.0
digitalocean ~> 2.16

Providers

Name Version
digitalocean 2.16.0
http 2.1.0
local 2.1.0

Modules

No modules.

Resources

Name Type
digitalocean_database_cluster.mysql resource
digitalocean_database_db.website1 resource
digitalocean_database_db.website2 resource
digitalocean_database_firewall.mysql resource
digitalocean_database_user.website1 resource
digitalocean_database_user.website2 resource
digitalocean_droplet.wordpress resource
digitalocean_firewall.wordpress resource
digitalocean_loadbalancer.wordpress resource
digitalocean_vpc.this resource
local_file.ansible_inventory resource
http_http.myip data source

Inputs

Name Description Type Default Required
do_token n/a string n/a yes
name_prefix n/a string "terraform2" no
region n/a string "fra1" no
ssh_fingerprint n/a string n/a yes

Outputs

Name Description
wordpress_lb_ip n/a

About

Deploy one or more highly available/load-balanced WordPress websites on DigitalOcean, with a dedicated MySQL cluster via Terraform and Ansible

Topics

Resources

License

Stars

Watchers

Forks