Setting up Digital Ocean DNS Records for Github Pages using Terraform

I recently transferred a few of my static sites over to Github Pages. It’s a fantastic, and low-cost (sometimes free) tool for hosting static content. Previously I had these sites running on Kubernetes in nginx containers with the majority of my services, but I wanted to provision DNS records for them in Digital Ocean, and there’s no better way to do that than with terraform.

If you also manage your DNS records in Digital Ocean, and are setting up a GitHub pages site — here’s how you can get started with terraform to manage these records easily and repeatably.

How To Use Terraform to setup DNS Records for GitHub Pages in Digital Ocean

We’ll first create a few files we need to get started.

touch main.tf
touch variables.tf
mkdir digitalocean_githubpages
touch digitalocean_githubpages/main.tf
touch digitalocean_githubpages/variables.tf
touch digitalocean_githubpages/dns.tf

With that taken care of, we can now add our Digital Ocean provider to both the main.tf and digitalocean_githubpages/main.tf files.

terraform {
required_providers {
digitalocean = {
source = "digitalocean/digitalocean"
version = "~> 2.0"
}
}
}
provider "digitalocean" {
token = var.digitalocean_token
}

You may notice we’re referencing a variable (var.digitalocean_token) that doesn’t yet exist. We can define this in variables.tf as well as digitalocean_githubpages/variables.tf

variable "digitalocean_token" {
type = string
description = "Digital Ocean Personal Access Token"
}

You can grab this token from the digital ocean console — we’ll need it later to create resources on your behalf.

Add in these additional variables to only the digitalocean_githubpages/variables.tf file

variable "tld" {
type = string
description = "The top level domain for the site"
}
variable "is_apex" {
type = bool
default = true
description = "Is this an apex domain? true or false"
}
variable "github_username" {
type = string
description = "The GitHub username hosting the pages: ?.github.io"
}

Defining DNS Records

With the basics setup, we’ll now define some basic variables we’ll need. In the digitalocean_githubpages/main.tf file add the following code:

locals {
github_pages_ipv4 = [
"185.199.108.153",
"185.199.109.153",
"185.199.110.153",
"185.199.111.153",
]
github_pages_ipv6 = [
"2606:50c0:8000::153",
"2606:50c0:8001::153",
"2606:50c0:8002::153",
"2606:50c0:8003::153",
]
}

These are the IPV4 and IPV6 records pointing to GitHub Pages that we’ll use to create records down the line. Make sure to check the docs in case these records change, but these are the current ones as of January 2022.

We’ll now need to define the domain and some records. Open the digitalocean_githubpages/dns.tf file and add the following:

resource "digitalocean_domain" "ghp_domain" {
name = var.tld
}

Next we’ll define our A records and match them to each one of the IPV4 addresses. Add the following to the same file. Using the count argument, we iterate over each one of the IPV4 addresses defined above and create a record in digital ocean with it.

resource "digitalocean_record" "ghp_domain_a" {
count = length(local.github_pages_ipv4)
domain = var.tld
type = "A"
ttl = 60
name = "@"
value = local.github_pages_ipv4[count.index]
depends_on = [
digitalocean_domain.ghp_domain,
]
}

We’ll now do the exact same with our IPV6 addresses, creating AAAA records. Add the following to the same file.

resource "digitalocean_record" "ghp_domain_aaaa" {
count = length(local.github_pages_ipv6)
domain = var.tld
type = "AAAA"
ttl = 60
name = "@"
value = local.github_pages_ipv6[count.index]
depends_on = [
digitalocean_domain.ghp_domain,
]
}

We’ll now define the www subdomain for any apex domains; ensuring www.example.com and example.com both work with the site. Add the following to the same file:

resource "digitalocean_record" "ghp_cname" {
count = "${var.is_apex == true ? 1 : 0}"
domain = var.tld
type = "CNAME"
ttl = 60
name = "www"
value = "${var.github_username}.github.io."
depends_on = [
digitalocean_domain.ghp_domain,
]
}

We’ve now finished creating our digitalocean_githubpages module. If you’re not familiar with the concept, a module in terraform is a repeatable set of resources that can be easily called with arguments, similar to calling a function or instantiating a class. For us, it makes it easy to implement multiple github pages sites for all your side projects.

Implementing The Module

In the main.tf file, add the following code; in it we are defining two example sites with the module we just created.

module "example1" {
source = "./digitalocean_githubpages"
is_apex = true
tld = "example1.com"
github_username = "your_github_username"
digitalocean_token = var.digitalocean_token
}
module "example2" {
source = "./digitalocean_githubpages"
is_apex = true
tld = "example2.com"
github_username = "your_github_username"
digitalocean_token = var.digitalocean_token
}

We define any variables the module requires to function, and pass the digitalocean token down so the module can access it.

Creating The Records

Now all that’s left to do is create our records. First, run terraform init to make sure everything is set up correctly.

terraform init

Next, run terraform plan to plan out the changes. If all goes correctly, you’ll be asked for your digitalocean_token which is the personal access token retrieved from the digital ocean console. Once that’s set, you should be faced with a log outlining the proposed resources to be added.

terraform plan

Once you’re comfortable with them, use the following command, followed by typing in “yes” to approve the changes and deploy your DNS records.

terraform apply

Final Thoughts

That’s it! That’s how I manage my DNS records in Digital Ocean for Github pages using terraform. Realistically, if you’re just setting up one personal site, it might make more sense for you to input the records manually. The advantages of terraform come from repeatability, and the ability to easily re-deploy everything if something goes wrong.

If you’re looking for an excuse to get more comfortable with terraform, I definitely recommend managing your DNS records with them. I can’t promise it’ll make DNS any less painful of an experience, but at least we’re learning. Best of luck!

Ryder Damen is a DevOps engineer by day, and also a DevOps engineer by night. He enjoys travelling, trying new things and making the web a stranger place.