Varnish Logo

Terraform and OpenTofu

Manage your Varnish CDN services, certificates and purge tokens as code with the Varnish provider for OpenTofu and Terraform.

The Varnish provider lets you manage your CDN setup as code. You describe services, domains, origins, settings, certificates and purge tokens in configuration files, and OpenTofu or Terraform creates and updates them for you.

The provider is open source and available at github.com/varnish/terraform-provider-varnish.

The provider is published in the OpenTofu Registry. Terraform Registry support is coming. Until then, Terraform users can build the provider locally.

What you can manage

ResourceDescription
varnish_cdn_serviceA CDN service with its domains, origins and settings
varnish_cdn_certificateAn uploaded TLS certificate
varnish_cdn_purge_tokenA token that can only invalidate cached content
varnish_org_userA user in your organization, from invite to member
Data sourceDescription
varnish_cdn_domain_dnsThe DNS records a domain needs, and its verification status
varnish_cdn_wizard_templatesThe configuration templates available to your organization
varnish_rolesThe role names you can give to varnish_org_user

Getting started with OpenTofu

Create an API access token

Create an API access token for your organization in the dashboard. The provider uses it for all requests. Treat it like a password.

Configure the provider

Create a main.tf file:

main.tf
terraform {
  required_providers {
    varnish = {
      source  = "varnish/varnish"
      version = "~> 0.1"
    }
  }
}

provider "varnish" {}

Set the token

Pass the token as an environment variable, so it never ends up in your files:

terminal
export VARNISH_ACCESS_TOKEN="<your-access-token>"

Initialize

terminal
tofu init

OpenTofu downloads the provider and verifies its signature.

Create a service

A service needs at least one domain and one origin:

main.tf
resource "varnish_cdn_service" "web" {
  domain {
    fqdn = "www.example.com"
    tls  = true
  }

  origin {
    name       = "default"
    host       = "origin.example.com"
    port       = 443
    enable_tls = true
    is_default = true
  }
}

# The DNS records to set at your DNS provider
data "varnish_cdn_domain_dns" "www" {
  service_id = varnish_cdn_service.web.id
  fqdn       = "www.example.com"
}

output "dns" {
  value = {
    cname    = data.varnish_cdn_domain_dns.www.expected_cname
    txt      = data.varnish_cdn_domain_dns.www.expected_txt
    verified = data.varnish_cdn_domain_dns.www.verified
  }
}

Review the changes and apply them:

terminal
tofu plan
tofu apply

The dns output shows the records your domain needs. Once they are in place, verified becomes true.

To use an apex domain such as example.com, set subdomain, for example subdomain = "www". Wildcard domains such as *.example.com are supported too.

Configure settings

The settings attribute holds the same configuration as the dashboard. The fields follow the configuration reference, written in snake_case:

main.tf
resource "varnish_cdn_service" "web" {
  # domain and origin blocks as above

  settings = {
    general = {
      first_byte_timeout = "10s"
    }

    query_params = {
      remove_query_parameters = { action = "sort" }
    }

    cookies = {
      on_cookie = { action = "remove" }
    }

    security = {
      https_redirect = true
      hsts           = true
    }

    # Apply settings only to matching requests
    overrides = [
      {
        name       = "cache-images-long"
        extensions = ["jpg", "png", "webp"]
        rules = [
          { string_id = "general.cacheableTTLOverride", value = jsonencode("7d") },
        ]
      },
    ]
  }
}

Only the settings you set are managed. Everything else keeps its current value, and changes made in the dashboard to those settings do not show up as a difference in your plan.

Removing a setting from your configuration stops managing it. It does not reset it to the default value.

See the configuration pages for what each setting does. The full example lists every field with its allowed values.

Use your own certificate

By default, the CDN issues certificates for your domains. To use your own certificate, upload it and attach it to a domain:

main.tf
resource "varnish_cdn_certificate" "example" {
  name        = "example-com"
  certificate = file("cert.pem")
  private_key = file("key.pem")
}

resource "varnish_cdn_service" "web" {
  domain {
    fqdn    = "www.example.com"
    tls     = true
    cert_id = varnish_cdn_certificate.example.id
  }

  # origin block as above
}
The private key is stored in your state file. Keep the state file in a secure backend.

Create a purge token

Purge tokens let other systems invalidate cached content:

main.tf
resource "varnish_cdn_purge_token" "ci" {
  label  = "ci-pipeline"
  expire = "8760h" # one year
}

output "purge_token" {
  value     = varnish_cdn_purge_token.ci.access_token
  sensitive = true
}

Read the token with tofu output -raw purge_token. It is only available for tokens created by OpenTofu or Terraform, not for imported ones.

Import existing services

To manage a service you already created in the dashboard, import it by its service ID:

import.tf
import {
  to = varnish_cdn_service.web
  id = "42"
}

Then generate the configuration for it:

terminal
tofu plan -generate-config-out=generated.tf

Review generated.tf, then run tofu apply to finish the import.

Terraform: build locally

Until the provider is in the Terraform Registry, build it from source. You need Go installed.

Build and install the provider

terminal
git clone https://github.com/varnish/terraform-provider-varnish.git
cd terraform-provider-varnish
go install .

This puts the binary in $(go env GOPATH)/bin.

Point Terraform to the local build

Add this to ~/.terraformrc. Replace the path with the output of go env GOPATH, followed by /bin:

~/.terraformrc
provider_installation {
  dev_overrides {
    "registry.terraform.io/varnish/varnish" = "/home/<user>/go/bin"
  }
  direct {}
}

Use it

Use the same main.tf as above. Skip terraform init, and run terraform plan and terraform apply directly. Terraform prints a warning that development overrides are in use. That is expected.

Remove the dev_overrides block once the provider is available in the Terraform Registry.

Reference