DigitalOcean, DNSimple and Terraform: A very short introduction.

I’ve spent the last few weeks diving into the world of DevOps, and one of the tools I’ve been wanting to play with is Terraform. This article is a quick walkthrough that explains how terraform can be used to spin up a droplet on DigitalOcean, deploy a static website to it and create a subdomain for it via DNSimple. First though, let’s look at the services we’ll be using…

DNSimple

DNSimple is a pretty powerful DNS and domain management service which I use to manage all my domains. They offer a personal plan for $5 per month, an intuitive interface for managing DNS and, crucially, an API for adding and editing records.

DigitalOcean

DigitalOcean provide small (and cheap) cloud servers — the smallest boxes cost $5 a month. Like DNSimple, they offer an API that allows us to programmatically spin up or spin down a server.

Terraform

I’ll let Terraform describe itself:

Terraform is a tool for building, changing, and versioning infrastructure safely and efficiently. Terraform can manage existing and popular service providers as well as custom in-house solutions.
Configuration files describe to Terraform the components needed to run a single application or your entire datacenter. Terraform generates an execution plan describing what it will do to reach the desired state, and then executes it to build the described infrastructure. As the configuration changes, Terraform is able to determine what changed and create incremental execution plans which can be applied.

What are we going to build?

We’re going to deploy a static website which has just one index.html page, and is in a folder called site in our project’s home directory. Here’s what we want to achieve:

  1. I can run terraform locally, providing a project name like myproject.
  2. Terraform will spin up a DigitalOcean droplet called myproject and deploy the site to it. It will then make that site available on http://myproject.dasmith.co.uk by adding the correct DNS records to DNSimple.

To do that, we need a terraform script that does the following:

  • Creates a new DigitalOcean droplet and enables passwordless SSH connections to it.
  • Updates Aptitude and installs nginx on the droplet.
  • Copy the contents of our site directory to nginx’s public folder on the droplet.
  • Creates an A record for a new subdomain on DNSimple, which points to our DO droplet.

Step 1 — Project Structure

We need to create a new directory to contain our project, and then make a directory called sites, which will hold our website. We also need to create a couple of terraform files. We’ll also add terraform.tfvars to our gitignore file and create a simple Readme. I’m going to call my project applejuice…

$ mkdir applejuice
$ cd applejuice
$ mkdir site
$ touch terraform.tfvars deploy.tf
$ echo "# Terraform Demo\n\nThis is a demo of Terraform, DigitalOcean and DNSimple" > README.md
$ echo "terraform.tfvars" > .gitignore

Next, we can put some HTML into an index.html file in our site directory, initialise our project as a git repo and commit our changes:

$ echo "<html><body>\n\t<h1>Hello World</h1>\n\t<p>It works! Whoop whoop</p>\n</body></html>" > site/index.html
$ git add . && git commit -m "Initial Commit"

Step 2 — DigitalOcean Setup

Once you’ve created an account on DigitalOcean and added your payment details, head over to the Account Settings, and the Security. We’re going to add an SSH Key to DigitalOcean. Follow the tutorial and add your public SSH key to your account, but stop at the point where you’re asked to click the Create Droplet button — we’re going to have Terraform do that for us.

Next, we’re going to generate an API token. Head to API then Tokens, and create a new token. Make sure you enable both Read and Write access, and copy the token.

Finally, we need to store these details somewhere. Add some code to your terraform.tfvars file. We’re going to create four variables:

  1. do_token is your DigitalOcean API token.
  2. ssh_fingerprint is the fingerprint for the SSH key you added to DigitalOcean. You can find it under the Security tab on your account page.
  3. pub_key and pvt_key are the local paths to the SSH private and public keys you created earlier.
do_token = "XXXXXXXXXXX"
ssh_fingerprint = "XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX"
pub_key = "~/.ssh/id_rsa.pub"
pvt_key = "~/.ssh/id_rsa"

Step 3 — DNSimple Setup

Head to your user settings on DNSimple and grab the API v1 token at the bottom. We need to add a couple of new lines to our terraform.tfvars file:

dnsimple_token = "XXXXXXXXXXXXX"
dnsimple_email = "your.email@somewhere.com"

Finally, check that you have set up at least one domain name on your DNSimple account. I’m going to be using dasmith.co.uk for the rest of this tutorial.

Step 4 — Write the Terraform deploy script

First, we need to create some variables in our deploy.tf file:

variable "do_token" {}
variable "dnsimple_token" {}
variable "project_name" {}
variable "pub_key" {}
variable "pvt_key" {}
variable "ssh_fingerprint" {}
variable "dnsimple_email" {}

These variables can have values assigned to them in a number of ways. We can include default values in our deploy.tf file, we can specify them as command line flags, or we can specify them in a terraform.tfvars file. The only variable that we haven’t populated from the tfvars file is the project_name. We’ll need to supply this at the command line later.

Next, we need to set up our two providers in our deploy.tf file. We’ll use the variables we created earlier to set the required details:

provider "digitalocean" {
token = "${var.do_token}"
}
provider "dnsimple" {
token = "${var.dnsimple_token}"
email = "${var.dnsimple_email}"
}

Now it’s time to create our DigitalOcean Droplet resource. We need to do a number of things:

  • Name the droplet based on the project name variable.
  • Provide a size, image and regione (we’re going to hard-code those, but we could easily variableize them).
  • Add out SSH fingerprint to the SSK Keys on the droplet.
  • Specify how Terraform should connect to the droplet, in our case using SSH and the local private key.
  • Specify a provisioner that will run some commands on the new droplet. We need to alter the path, run apt-get update, install nginx and remove anything in the default nginx public directory.
  • Specify another provisioner that copies the contents of our site directory to the droplet, in the nginx public directory.

Here’s the code that achieves that:

resource "digitalocean_droplet" "web" {
name = "${var.project_name}"
size = "512mb"
image = "ubuntu-16-04-x64"
region = "lon1"
ssh_keys = [
"${var.ssh_fingerprint}"
]
connection {
user = "root"
type = "ssh"
private_key = "${file(var.pvt_key)}"
timeout = "2m"
}
provisioner "remote-exec" {
inline = [
"export PATH=$PATH:/usr/bin",
"sudo apt-get update",
"sudo apt-get install -y nginx",
"sudo rm /var/www/html/*"
]
}
provisioner "file" {
source = "site/"
destination = "/var/www/html"
}
}

Finally, we need to create a second resource which will create a new DNS Record on DNSimple, using the project name variable for the name, and the IP address of our newly-created droplet as the target.

resource "dnsimple_record" "www" {
domain = "dasmith.co.uk"
name = "${var.project_name}"
value = "${digitalocean_droplet.web.ipv4_address}"
type = "A"
}

Step 5 — Running Terraform

Before applying the terraform configuration changes, we should dry-run the script. We can do that with

$ terraform plan -var 'project_name=applejuice'

This will provide output that looks something like this:

Output from terraform plan command.

Finally, we can execute the script with the terraform apply command:

$ terraform apply -var 'project_name=applejuice'

This will spin up our droplet and configure an A record for us…

DigitalOcean Dashboard
DNSimple Dashboard

If we visit http://applejuice.dasmith.co.uk, we should see our website.


Spinning it all down

Spinning down the whole thing down is ridiculously simple. We can just run terraform destroy.

$ terraform destroy -var 'project_name=applejuice'

And there we have it.


If you enjoyed this article, please recommend it on medium, or tweet about it 👍