Subscribe to receive notifications of new posts:

Deploy Workers using Terraform

2018-09-13

4 min read
cf-plus-terraform-@2x-1

Today we're excited to announce that Cloudflare Workers are now supported in the Cloudflare Terraform Provider.

Terraform is a fantastic tool for configuring your infrastructure. Traditionally if you wanted to spin up, tear down or update some of your infrastructure you would have to click around on a website or make some API calls, which is prone to human error. With Terraform, you define your infrastructure in simple, declarative configuration files and let Terraform figure out how to make the API calls for you. This also lets you treat your infrastructure like your code. You can check your Terraform configuration files into version control and integrate them into your normal software development workflow.

Terraform integrates with many infrastructure providers including Cloudflare. If you'd like to read more about setting up Terraform with Cloudflare, check out Getting started with Terraform and Cloudflare. In this post, I'm going to focus specifically on how to integrate Cloudflare Workers with Terraform.

In this example we're going to create partyparrot.business, and we're going to serve the whole site out of a worker without any origin server. We're starting from scratch here, but if you're already using Cloudflare workers and want to migrate to managing your workers with Terraform, you'll need to import your existing script and routes so that Terraform knows about them. See the "Importing your existing workers" section at the end.

Prerequisites

  • Install Terraform

  • Provide your Cloudflare credentials via environment variables

    • Set CLOUDFLARE_EMAIL to your email address

    • Set CLOUDFLARE_TOKEN to your Cloudflare API key

    • If you're on an Enterprise plan and want to use multiple scripts, you'll also need to set CLOUDFLARE_ORG_ID to your account ID. You can find your account ID by using the List Accounts API

Create the Terraform config file

Create a file with any name and give it a .tf file extension. This is where we'll define our Terraform resources. In this file, first we'll need to setup the Cloudflare provider:

provider "cloudflare" {}

You could define your credentials in this file, but in general it's better to use environment variables so that you can check the configuration file into version control without including any private data.

Next we're going to create a variable named zone. One of the benefits about defining the zone in a variable as opposed to hard-coding it is that you can setup a separate staging domain and use the same Terraform configuration as your production domain. See the documentation for more information on working with variables.

variable "zone" {
  default = "partyparrot.business"
}

Setting up the worker script

Now let's write our worker script. If you're looking for inspiration, check out some Worker recipes. For this example, I'll use this script and name it party_parrot_worker.js.

Next we need to add a cloudflare_worker_script resource to our Terraform config and reference the script file. Open your .tf file and add the following:

resource "cloudflare_worker_script" "main_script" {
  zone = "${var.zone}"
  content = "${file("party_parrot_worker.js")}"
}

If you're new to Terraform, check out the Terraform Resource documentation to learn more about this schema. Here we provide 2 parameters, the zone which references the variable we defined earlier and content which references the file we just created.

NOTE: The Cloudflare Enterprise plan supports using multiple (named) scripts. To use this, the parameters will be slightly different. Remove the zone parameter since named scripts are not tied to a particular zone and instead add a name parameter to define the name of the script. See the cloudflare_worker_script documentation for an example.

Setting up the worker routes

In order for the worker to start handling traffic, we'll also need to define at least one route. To do so, add a cloudflare_worker_route resource to the Terraform config.

resource "cloudflare_worker_route" "catch_all_route" {
  zone = "${var.zone}"
  pattern = "*${var.zone}/*"
  enabled = true
  depends_on = ["cloudflare_worker_script.main_script"]
}

Just like with the script resource, the zone parameter references the variable we defined earlier.

The pattern parameter defines which requests should be sent to the worker. In this example we use a route pattern like *partyparrot.business* which will match all traffic. If, however, you only want your worker to handle a subset of requests to your zone, you can define a more specific pattern like mysubdomain.example.com/* or *example.com/mypath*. More information on route patterns is available here.

The enabled parameter specifies that requests that match the pattern should run the worker. Alternatively, you can set enabled to false which would mean that any requests that match the pattern should not run the worker. You can create multiple route patterns, and more-specific route patterns apply before less-specific route patterns. For example, you could create one route pattern like example.com/assets/* and set enabled = false then create another pattern like *example.com* and set enabled = true. This would enable the worker for all traffic except for requests that match example.com/assets/*.

Finally, we set depends_on to point to the script resource we created above. In general, Terraform will try to create resources in parallel, but you may get an error if you try to create a route before you have a script. By using the depends_on parameter, Terraform will know to create the script first before creating the route.

NOTE: As with the script resource, some of the parameters are different if you're on the Enterprise plan and using multiple scripts. Remove the enabled parameter and instead set script_name = "${cloudflare_worker_script.your_script_resource.name}" to specify which script the route should run. By directly referencing the script resource using this syntax, Terraform already knows that the route depends on the script, so you can also remove the depends_on parameter. You can see more details in the cloudflare_worker_route documentation.

Applying the Terraform config

Now that we've defined our script and route resources in the config file, we're ready to deploy! To initialize Terraform, run terraform init

$ terraform init

Initializing provider plugins...

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

Now to deploy the changes, run terraform apply. Terraform will show you a preview of the changes it will make.

$ terraform apply

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  + cloudflare_worker_route.catch_all_route
      id:           <computed>
      enabled:      "true"
      multi_script: <computed>
      pattern:      "*partyparrot.business/*"
      zone:         "partyparrot.business"
      zone_id:      <computed>

  + cloudflare_worker_script.main_script
      id:           <computed>
      content:      "...omitted for brevity..."
      zone:         "partyparrot.business"
      zone_id:      <computed>


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

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value:

If everything looks good, type yes and press return to apply the changes.

cloudflare_worker_script.main_script: Creating...
  content: "" => "...omitted for brevity..."
  zone:    "" => "partyparrot.business"
  zone_id: "" => "<computed>"
cloudflare_worker_script.main_script: Creation complete after 1s (ID: zone:partyparrot.business)
cloudflare_worker_route.catch_all_route: Creating...
  enabled:      "" => "true"
  multi_script: "" => "<computed>"
  pattern:      "" => "*partyparrot.business/*"
  zone:         "" => "partyparrot.business"
  zone_id:      "" => "<computed>"
cloudflare_worker_route.catch_all_route: Creation complete after 0s (ID: af595c1bb7cd4d1698c4d6cbcb364662)

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

Congratulations, your worker script and route are deployed! You can see the example script running at partyparrot.business.

As you make changes to your script or Terraform config, you can run terraform apply again and Terraform will figure out what's changed and deploy any updates.

Importing your existing workers

If you're already using Cloudflare Workers but want to start managing them via Terraform, you'll need to let Terraform know about your existing configuration so it knows how to apply changes going forward.

First you’ll need to create your .tf file and add cloudflare_worker_script and cloudflare_worker_route resources for all of your existing scripts and routes.

Next you'll need to individually run the appropriate terraform import ... command for each script and route resource. The import command takes two arguments:

  • the identifier of the resource that you defined in your .tf file (ex: cloudflare_worker_script.main_script or cloudflare_worker_route.catch_all_route)

  • an ID that's used to lookup the resource from the cloudflare API. See the cloudflare_worker_script and cloudflare_worker_route documentation for more information.

Wrapping up

The complete script and terraform configuration file for this example are hosted on Github.

Whether you're already using Cloudflare Workers or just getting started, Terraform can be a great way to manage your Workers configuration. If you're interested in learning more, here's a few useful links:

Cloudflare's connectivity cloud protects entire corporate networks, helps customers build Internet-scale applications efficiently, accelerates any website or Internet application, wards off DDoS attacks, keeps hackers at bay, and can help you on your journey to Zero Trust.

Visit 1.1.1.1 from any device to get started with our free app that makes your Internet faster and safer.

To learn more about our mission to help build a better Internet, start here. If you're looking for a new career direction, check out our open positions.
Cloudflare WorkersServerlessJavaScriptTerraformProduct NewsProgrammingDevelopersDeveloper Platform

Follow on X

Cloudflare|@cloudflare

Related posts

October 31, 2024 1:00 PM

Moving Baselime from AWS to Cloudflare: simpler architecture, improved performance, over 80% lower cloud costs

Post-acquisition, we migrated Baselime from AWS to the Cloudflare Developer Platform and in the process, we improved query times, simplified data ingestion, and now handle far more events, all while cutting costs. Here’s how we built a modern, high-performing observability platform on Cloudflare’s network. ...