1. How we manage WordPress website with Terraform, Chef and GitHub

How we manage WordPress website with Terraform, Chef and GitHub

water drop falling

Our website twindb.com is built on WordPress software and has always been. A while ago we decided the website needs a better look. But not only that. Managing our old website was quite laborious and manual process which goes strongly against our culture at TwinDB to do things right. Few weeks ago we migrated to the new website and I’m so proud to share with the community how we provision a fully automated WordPress website with Terraform, Chef and GitHub.


We run our stuff in AWS. We wanted to have better control of our AWS infrastructure. Most of old infrastructure was created manually in AWS console which is probably the worst way to manage AWS. We needed Terraform to implement Infrastructure as Code and keep it in Github.

We needed to provision several web servers and use load balancers for load share.

We needed reliable and repeatable way to provision a web server instance without even SSH-ing to it.

The website lives a long life, but it’s not static. We needed to update plugins versions, install new ones. WordPress itself also must be kept up-to-date.

We needed a way to work with a third party who wrote the code and keeps maintaining it – fixing bugs, adding new features. We needed better grasp of what is being changed on our website.

This post is going to describe how we solved each of these problems. Let’s start with Terraform.


If you don’t know, Terraform is a kind of Chef/Puppet for a cloud. It implements so called Infrastructure As Code approach. You define the desired state – what VPC, subnets, routing tables, security groups, instances, load balancers you need, and Terraform converges your cloud to that state. Terraform manages everything in your cloud – from user accounts to network, instances and S3 buckets. It’s quite important to manage all entities with Terraform, otherwise bugs and unpredicted states are guaranteed. It’s like with cars – you can drive either right side or be Britain but not mix.

That’s why we created a brand new account that is fully managed by Terraform and migrated all services to the new account.

For the website we created web server instances, one database instance, and a load balancer.

There are two instance for web servers:

There is one load balancer. It also terminates HTTPS.

And one database instance:

Now, if I want to replace one instance I will simply terminate it, then run terraform apply – it will launch a fresh instance. When Chef provisions the instance the load balancer will add it into rotation. I can also add remove web servers depending on load on the website.


To provision instances we use Chef. When Chef bootstraps a new web server it performs these steps:

  1. Configures software repositories.
  2. Installs packages.
  3. Installs and configures Apache + PHP.
  4. Configures backups.
  5. Installs latest WordPress.
  6. Installs the website from GitHub.
  7. Installs the website configs.
  8. Syncs the media library with a shared S3 bucket.

From then on Chef regularly pulls latest website changes from GitHub and syncs the media library.

Software Repositories, Apache and PHP

Let’s start with the repos. We will need TwinDB, Percona, MySQL Community, and Epel repositories. It’s pretty straightforward.

Let’s see now what we need to install Apache and PHP.

Configure TwinDB Backups

To enable backups on the host we need to install a twindb-backup package and its configuration file.

Why do we need backups if the instance can be safely discarded and rebuilt, you may wonder? The main reason for that is to preserve a file cache, so when the instance is put into rotation it’s already warmed up. And Phoebe recommends doing so.


Chef installs the latest WordPress only one time – at the instance bootstrap. If I need to upgrade wordpress version I will terminate this instance and bootstrap a new one. We also keep plugins in the website repo, so we remove akismet plugin that comes with WordPress. That’s it, no black magic here.


The website is the most interesting part. We had to solve many problems here.

We keep the website code on GitHub. In the repo we store plugins and TwinDB theme. Amazing Fruiful Code team created the design and developed code for TwinDB.com. Thank you guys!

Chef clones this repo when it bootstraps an instance and pulls changes when the instance is operational.

So, when I want to update a plugin version I put the new code into the repo, push it and in 30 minutes the new version is deployed on all web servers.

When Fruitful Code makes changes they commit them to the master branch. For extra security we might require a PR before the code gets into the master.

Then Chef restores a media library and cache from a backup.

Then Chef determines the current database host and saves it in a file. The WordPress config reads that file to define DB_HOST. It is a kind of poor man high availability :).

And the last step is to sync the media library. The matter is it’s a bad practice to store media files in git. Same time I didn’t want to deal with any kind of shared volumes. So, instead, Chef syncs media library with an S3 bucket every 30 minutes.


Our new website is live few weeks. So far I like the result. Since then we installed new plugins, upgraded the plugins and wordpress itself, made numerous changes to the website itself, wrote couple of posts. This architecture proved to be viable.

Probably, in future we will configure staging environment and integration tests before putting changes in production. But so far, so good.

Previous Post Next Post

Comments are closed.