Terraform + CloudFlare Automated Domain Setup

Returning to the roots of multifaceted wisdom.

connect


July 1, 2018

Terraform + CloudFlare Automated Domain Setup

Terraform + CloudFlare Automated Domain Setup

I just completed setting up 10 domains on CloudFlare and wondered to myself… Why…

It’s definitely something I do quite often and there is always room for error. And honestly, I would love anything that would help me speed this stuff up so I can get to the actual development.

Well, Terraform helps me setup my stacks much more efficiently and gives me near complete control over things like CloudFlare using CI type deployment and source control. Let’s set it up!

TL;DR check out the code on GitHub. Download Terraform.

Installing Terraform

First thing you’ll need is Terraform. It’s an open source project that has been getting plenty of traction. It differs from other management libraries like Chef, Kubernetes, Ansible, etc. in that it is built for cross-provider stack setup. So I can have source-controlled files that control DigitalOcean, AWS, CloudFlare, Google Cloud, and anything else I want, all at once. So here is how it starts:

brew install terraform

Create a directory to store your stack configuration and then run:

touch cloudflare.tf && terraform init

Get API Key from CloudFlare

In order to continue you will need your *email* and the CloudFlare API Token found on this page under Global API Key.

API Key

If your domain isn’t already setup at CloudFlare, you’ll actually have to set that up too. Just click + Add Site and then follow the instructions. After it’s setup you’ll be able to stick most of your CF configuration in source control.

Setup the Configuration

We will be using Terraform variables to give us access to override them from command line. The first few lines of the file look like this:

variable "email" {}
variable "token" {}
variable "domain" {}

provider "cloudflare" {
  email = "${var.email}"
  token = "${var.token}"
}

This gives us three variables: email (email used to login to CloudFlare), token (your api token from CloudFlare), and domain. It then sets up the provider for CloudFlare. If you’re curious to the other options this provider has please check the docs.

Setup the WWW and non-WWW domains

Now we can setup the domain name for *www.yoursite.com* and yoursite.com. This is done by the following:

# Setup the domain
resource "cloudflare_record" "main" {
  domain  = "${var.domain}"
  name    = "@"
  value   = "192.168.0.11"
  type    = "A"
  proxied = true
}

# Setup the www CNAME for your domain
resource "cloudflare_record" "main-www" {
  domain  = "${var.domain}"
  name    = "www"
  value   = "${var.domain}"
  type    = "CNAME"
  proxied = true
}

The ${var.domain} is how you reference the variables throughout the configuration file. There is a lot of flexibility here and would be worth reading through the docs more. If you don’t want to use the CloudFlare proxy you can just set those to false.

Setting up the Google MX Configuration

Google has 5 mail servers that every developer knows by heart. The servers are:

1 ASPMX.L.GOOGLE.COM.
5 ALT1.ASPMX.L.GOOGLE.COM.
5 ALT2.ASPMX.L.GOOGLE.COM.
10 ALT3.ASPMX.L.GOOGLE.COM.
10 ALT4.ASPMX.L.GOOGLE.COM.

And we configure these by adding the following lines to our code:

# Setting up Google MX
resource "cloudflare_record" "google-mx-record-aspmx" {
  domain   = "${var.domain}"
  name     = "@"
  value    = "aspmx.l.google.com"
  type     = "MX"
  priority = 1
}

resource "cloudflare_record" "google-mx-record-alt1" {
  domain   = "${var.domain}"
  name     = "@"
  value    = "alt1.aspmx.l.google.com"
  type     = "MX"
  priority = 5
}

resource "cloudflare_record" "google-mx-record-alt2" {
  domain   = "${var.domain}"
  name     = "@"
  value    = "alt2.aspmx.l.google.com"
  type     = "MX"
  priority = 5
}

resource "cloudflare_record" "google-mx-record-alt3" {
  domain   = "${var.domain}"
  name     = "@"
  value    = "alt3.aspmx.l.google.com"
  type     = "MX"
  priority = 10
}

resource "cloudflare_record" "google-mx-record-alt4" {
  domain   = "${var.domain}"
  name     = "@"
  value    = "alt4.aspmx.l.google.com"
  type     = "MX"
  priority = 10
}

To simplify things, @dsifford shared a great hack where you can interpolate the MX records with the count method:

resource "cloudflare_record" "mx-gsuite" {
  count    = 5
  domain   = "${var.domain}"
  name     = "@"
  type     = "MX"
  value    = "${count.index == 0 ? "" : "alt${count.index + 1}."}aspmx.l.google.com"
  priority = "${abs(element(list("1", "5", "5", "10", "10"), count.index))}"
}

Running the Configuration

Now the moment we’ve been waiting for… We have Terraform setup, we have CloudFlare creds copied, and we’ll finally be able to forget those MX records :P

terraform apply -var email=jon@awesome.io -var token=111111111111111111111 -var domain=myawesomedomain.com

You can see the variables specified here, they will be injected into the configuration and then it will give you a plan of action and allowing you to view all of the changes before going live. Just type *yes* and you’ll see all the magic update your CloudFlare configuration.

Now you can run that command in your favorite CI provider and any time you trigger the build it will update your CloudFlare domain settings (I personally don’t like to do this, but you could if you wanted to :D).

The complete code is below. It is also available on GitHub.

Here’s to automation!

comments powered by Disqus