Deploying Discourse with Terraform

Deploying Discourse with Terraform

Sep 03, 2014 | Jack Pearkes

In this blog post, we'll show how Terraform can create a running instance of Discourse on DigitalOcean in one command.

Following the release of Terraform 0.2, we wanted to publish the first of several examples of using Terraform to automate the creation and management of infrastructure.

Terraform is abstract, so it can be hard to grasp and understand it's capabilities without seeing and using it in a real world example. Even if you don't intend to keep Discourse running, this may be a good chance to learn more about Terraform.

» Discourse

Discourse is a discussion platform "built for the next decade of the Internet". That means it uses modern frameworks and tools to run. Because of this, installing Discourse can be challenging for new and inexperienced users.

Terraform, of course, is intended for a technical audience, but there's also potential to build tooling around it to take advantage of it's automation and friendly declarative configuration.

Discourse 1.0 was just released, so we find it fitting to use it to see Terraform in action. This configuration was based on the beginner installation guide published by Discourse.

» Preparation Steps

Before running terraform apply, you'll need to have accounts and access information for the configured providers.

Note: This example uses the DigitalOcean and Mailgun providers, but you could modify the configuration to use any other Terraform providers in place or in addition, like Route53 or DNSimple. For a full list of providers, visit the documentation.

  1. Access or create a DigitalOcean Account
    • Sign up or log in
    • Get a write-enabled access token
    • Add your SSH key and retrieve the ID with curl -X GET "" -H "Authorization: Bearer $ACCESS_TOKEN"
  2. Access or create a Mailgun Account
  3. Select your domain ( and point the nameservers at DigitalOcean.

» Getting the Configuration

Terraform is configured by .tf files. By default, Terraform collects all *.tf files in a directory and merges them together.

You'll need to clone the following example repository with Git:

$ git clone

Once the repository is retrieved from GitHub, we can try running Terraform.

» Running the Plan Command

Although not required for a terraform apply, terraform plan helps you visualize what Terraform will do. In this case, you should see output similar to the following:

$ terraform plan \
    -var 'developer_email=YOUR_ACCESS_KEY' \
    -var 'smtp_password=YOUR_SECRET_KEY' \
    -var 'domain=YOUR_DOMAIN' \
    -var 'ssh_key_id=YOUR_SSH_KEY_ID' \
    -var 'do_token=YOUR_DO_TOKEN' \
    -var 'mailgun_key=YOUR_MAILGUN_KEY' \
    -var 'ssh_key_path=YOUR_KEY_PATH'

+ digitalocean_domain.discourse
    ip_address: "" => "${digitalocean_droplet.discourse.ipv4_address}"
    name:       "" => "YOUR_DOMAIN"

+ digitalocean_droplet.discourse
    backups:              "" => "<computed>"
    image:                "" => "ubuntu-14-04-x64"
    ipv4_address:         "" => "<computed>"
    ipv4_address_private: "" => "<computed>"
    ipv6:                 "" => "<computed>"
    ipv6_address:         "" => "<computed>"
    ipv6_address_private: "" => "<computed>"
    locked:               "" => "<computed>"
    name:                 "" => "discourse"
    private_networking:   "" => "<computed>"
    region:               "" => "nyc2"
    size:                 "" => "2gb"
    ssh_keys.#:           "" => "1"
    ssh_keys.0:           "" => "YOUR_SSH_KEY_ID"
    status:               "" => "<computed>"

+ mailgun_domain.mail
    name:                "" => "YOUR_DOMAIN"
    receiving_records.#: "" => "<computed>"
    sending_records.#:   "" => "<computed>"
    smtp_login:          "" => "<computed>"
    smtp_password:       "" => "YOUR_SECRET_KEY"
    spam_action:         "" => "disabled"
    wildcard:            "" => "<computed>"

If you're happy with the output, you can move on to apply and create the resources.

» Running the Apply Command

$ terraform apply \
    -var 'developer_email=YOUR_ACCESS_KEY' \
    -var 'smtp_password=YOUR_SECRET_KEY' \
    -var 'domain=YOUR_DOMAIN' \
    -var 'ssh_key_id=YOUR_SSH_KEY_ID' \
    -var 'do_token=YOUR_DO_TOKEN' \
    -var 'mailgun_key=YOUR_MAILGUN_KEY' \
    -var 'ssh_key_path=YOUR_KEY_PATH'

This will create your infrastructure, showing you the output along the way. In this example, the following steps occur:

  1. The domain is created on Mailgun.
  2. The droplet (server) is created, provisioned with SMTP details and other configurations.
  3. The DNS records are created for mail and the application, using the IP addressed assigned to the previously created droplet.

The whole process takes some time, depending on several factors, as the provisioner on the server is installing, configuring and restarting Discourse. Under the hood, this uses Docker, which Terraform happily provisions on top of the DigitalOcean droplet.

Additionally, DigitalOcean DNS may take some time to propagate.

If you're interested in seeing detailed logs of what Terraform is doing, run the command with TF_LOG=1 ... prepended.

» Conclusion

Setting up Discourse with Terraform is an interesting example of what kind of automation is possible.

Part of the value of Terraform is how it combines resources, as demonstrated with Mailgun, and the resulting provisioning of SMTP credentials for the application to read.

If you're interested in learning more about Terraform, follow the links below.

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now