Using Terraform with DigitalOcean

In this post I’m going to use Terraform to define and launch a DigitalOcean server and a DNS DigitalOcean A Record.


  1. DigitalOcean Account.
  2. A DigitalOcean API access token. Follow the instructions here


Terraform is a tool created by HashiCorp, best known as the creators of Vagrant. Terraform allows you to define and launch your servers infrastructure, using a declarative language.

Some of the supported providers are: DigitalOcean, Azure, AWS , and Google Cloud just to name a few.

Terraform Providers

A provider is responsible for understanding API interactions and exposing resources. For example, the DigitalOcean Provider can create resources such Servers and DNS records using the DigitalOcean API

Terraform Resources

Resources are a component of your infrastructure. It might be some low level component such as a physical server, virtual machine, or container.

Terraform Provisioners

When a resource is initially created, provisioners can be executed to initialize that resource.

Installing Terraform

  1. Download the correct package for your system here
  2. unzip in a directory referenced by PATH, so you can run the terraform command easily.
    • eg. unzip ~/Downloads/ -d /usr/local/bin Now you should be able to run the terraform command.
$ terraform version
$ Terraform v0.6.8

Create a Terraform Configuration Project

mkdir ~/terraform-digitalocean-example
cd ~/terraform-digitalocean-example

Create a provider configuration

Create a file called


Add the following contents:

variable "do_token" {} #Your DigitalOcean token
variable "pub_key" {}  #Public Key to be installed in your DigitalOcean server
variable "pvt_key" {}#Private Key Terraform will use to connect to your new server
variable "ssh_fingerprint" {}#SSH Fingerprint

provider "digitalocean" {
token = "${var.do_token}"

Create a Server Resource

Create a file called


Add the following contents:

resource "digitalocean_droplet" "example_mydomain" {
	image = "ubuntu-14-04-x64"
	name = ""
	region = "nyc2"
	size = "512mb"
	private_networking = true
	ssh_keys = [

	connection {
		user = "root"
		type = "ssh"
		key_file = "${var.pvt_key}"
		timeout = "2m"

  provisioner "remote-exec" {
      inline = [
        "echo 'I might use puppet or ansible to provision my server here'",

connection: Allows Terraform to connect to your server via ssh.

privisioner: You can run different types of provisioners to provision your server.

Create a DNS A Record Resource

I’m assuming that you own a domain and and it’s already managed with DigitalOcean, if you don’t you can follow this post.

Create a file called


Add the following contents:

resource "digitalocean_record" "A-example" {
  domain = ""
  type = "A"
  name = "example"
  value = "${digitalocean_droplet.example_jumlabs.ipv4_address}"

Note: Remember to change with your own domain name.

Add Password-less SSH Key to DigitalOcean Cloud

If you have not already added a password-less SSH key to your DigitalOcean account, do so by following this tutorial.

Generate your ssh_fingerprint

Assuming that your private key is located at ~/.ssh/id_rsa, run :

ssh-keygen -lf ~/.ssh/ | awk '{print $2}'

This will output your Fingerprint. Something similar to this:


You will need this Fingerprint later.

Define Configuration Variables Values

Remember this? :

variable "do_token" {} #Your DigitalOcean token
variable "pub_key" {}  #Public Key to be installed in your DigitalOcean server
variable "pvt_key" {}#Private Key Terraform will use to connect to your new server
variable "ssh_fingerprint" {}#SSH Fingerprint

We are almost ready to run our Terraform configuration, but we still need to define a value for this variables. Terraform has a few ways of passing the value of this variables when you finally apply your configurations, I personally liked the file option.

Create a file called terraform.tfvars:

vi terraform.tfvars

Add the follow contents

do_token = "<your_digital_ocean_personal_token>"
pub_key = "/Users/<user>/.ssh/"
pvt_key = "/Users/<user>/.ssh/id_rsa"
ssh_fingerprint = "<your_ssh_fingerprint>"

Warning: If you are going to version control your Terraform Configuration Project, you should add this file to .gitignore, since it contains personal sensitive information.

Reviewing you Plan


terraform plan

It will output something like this:

+ digitalocean_droplet.example_mydomain
    image:                "" => "ubuntu-14-04-x64"
    ipv4_address:         "" => "<computed>"
    ipv4_address_private: "" => "<computed>"
    ipv6_address:         "" => "<computed>"
    ipv6_address_private: "" => "<computed>"
    locked:               "" => "<computed>"
    name:                 "" => ""
    private_networking:   "" => "1"
    region:               "" => "nyc2"
    size:                 "" => "512mb"
    ssh_keys.#:           "" => "1"
    ssh_keys.0:           "" => "e7:42:16:d7:e5:a0:43:23:82:7d:a3:59:cf:9e:92:f3"
    status:               "" => "<computed>"

+ digitalocean_record.A-example
    domain:   "" => ""
    name:     "" => "example"
    port:     "" => "<computed>"
    priority: "" => "<computed>"
    type:     "" => "A"
    value:    "" => "${digitalocean_droplet.example_mydomain.ipv4_address}"
    weight:   "" => "<computed>"

Plan: 2 to add, 0 to change, 0 to destroy.

It basically describes the actions Terraform will take at the time you actually apply it. If you have used git, you can think of this as a ‘git status’, something you might like to run before «committing» your changes.

Applying Your Configuration

So we are ready to actually create our resources.


terraform apply

Now yo can go a grab a cup of coffee while terraform applies your configuration.

At the end it will output something like this:

  id = <some_id>
  image = ubuntu-14-04-x64
  ipv4_address = <generated_ip>
  ipv4_address_private = <generated_ip_address>
  locked = false
  name =
  private_networking = true
  region = nyc2
  size = 512mb
  ssh_keys.# = 1
  ssh_keys.0 = <key_fingerprint>>
  status = active
  id = <some_id>
  domain =
  name = example
  port = 0
  priority = 0
  type = A
  value = <some_ip>
  weight = 0

Note: Remember that DigitalOcean might charge you for the time this resources are alive. If you don’t want to keep them you can


terraform destroy

Terraform vs Ansible/Chef/Puppet

There’s actually a difference between Terraform and provisioning tools such Ansible. Terraform allows you to define your infrastructure resources, you still need something to provision those resources, in that case you can use something like Ansible to do that Job.


Terraform is a tool for defining and manage infrastructure resources for several providers, from physical servers to the cloud. This allows easily reproduce common definitions to scale your infrastructure at will. You still need provisioning tools such Ansible to provision your servers.

I’ll write post about provisioning with Ansible later. Wait for it!!


comments powered by Disqus