Manage DNS with Terraform
The Domain Chief provider for Terraform and OpenTofu manages the hosted DNS records, web redirects and mail forwards of your domains as code. DNS changes go through the same review as the rest of your infrastructure, and a plan shows every change before it is made.
The provider manages domains that are already in Domain Chief. It does not register, transfer, renew or delete domains. Do that in Domain Chief or through the API.
This guide covers setting up the provider, managing records and importing a zone you already have. The provider documentation on the Terraform Registry describes every resource, data source and attribute.
Before you start
Domain requirements
The provider manages DNS records, web redirects and mail forwards of domains that use Domain Chief hosted DNS. Mail forwards also need mail forwarding to be enabled for the domain. Mail forwarding is a paid feature, so the provider does not enable it. Enable it in Domain Chief first.
Create a token
Create a team access token for the team that owns the domains. Keep only the scopes of the resources you use:
| Resource or data source | Scope |
|---|---|
domainchief_dns_record, domainchief_dns_records | domainchief:dns:write |
domainchief_web_redirect | domainchief:redirects_web:write |
domainchief_mail_forward | domainchief:redirects_mail:write |
domainchief_domain, domainchief_domains | domainchief:domains:read |
A write scope also allows reading, so domainchief:dns:write covers listing records with domainchief_dns_records. See scopes for what each scope allows.
The token can change every DNS record of every domain in the team. Store it in the secret store of your CI system or Terraform runner, never in your configuration or state backend files.
Configure the provider
Add the provider to your configuration:
Code
Set the token in the DOMAINCHIEF_API_TOKEN environment variable and initialize the working directory:
Code
OpenTofu uses the same configuration. Run tofu init instead.
Manage records
DNS records
Each domainchief_dns_record is one record. Leave out name for the domain itself:
Code
Write records the way you are used to. @ for the domain itself, uppercase names, hostnames with a trailing dot and TXT content with or without surrounding quotes are all accepted and do not show up as changes in later plans.
The TTL must be one of the values hosted DNS supports, such as 300 or 3600. A plan fails for other values instead of rounding them.
Web redirects
A domainchief_web_redirect redirects the domain itself or one of its subdomains. Domain Chief creates the DNS records the redirect needs, so do not add domainchief_dns_record resources for the same names:
Code
A redirect of the domain itself also redirects www unless you set include_www = false.
Mail forwards
A domainchief_mail_forward forwards one address, or every address without its own mail forward when the alias is *:
Code
Like web redirects, mail forwarding creates its own MX, SPF and DKIM records. Do not manage those records as domainchief_dns_record resources.
Import an existing zone
Records you created in Domain Chief or through the API are not in your Terraform state. Import them, so Terraform manages the existing records instead of creating duplicates next to them. Importing needs Terraform 1.5 or OpenTofu 1.6 or later.
Generate import blocks
Each import needs the ID of the record. The domainchief_dns_records data source lists every record of a domain, and a temporary discover.tf file turns that list into an import block for each record:
Code
Read the records and write the import blocks to a file:
Code
The apply only reads the records and changes nothing. imports.tf now contains an import block for every record you manage yourself:
Code
The data source marks records that Domain Chief manages with managed_by: web_redirect, mail_forwarding or acme_challenge. Those are skipped because Domain Chief maintains them for you. Manage the web redirects and mail forwards themselves with their own resources instead. Import those with the IDs from list web redirects and list mail forwards, in the form example.com/$ID.
Generate the configuration
Let Terraform write the resource configuration for the imported records:
Code
Review dns.tf. The generated resources also list attributes with their default values, such as comment = null, metadata = null and priority = 0, which you can remove. Then import the records:
Code
The apply imports the records without changing them. The final plan reports no changes, because Terraform now manages the zone.
Keep Terraform and Domain Chief in sync
Once Terraform manages a zone, make changes in your configuration:
- A record changed in Domain Chief or through the API shows up as a change in the next plan, and the next apply reverts it.
- A record deleted outside Terraform, for example by clearing or resetting the zone, is created again by the next apply.
- Records with a
managed_byvalue belong to their feature. Change them through the web redirect, mail forwarding or ACME client instead. - Metadata keys starting with
domainchief:are reserved for Domain Chief. You cannot set them and Terraform does not track them.
The provider applies changes to one domain one at a time. When another change to the same domain is running, for example from a second Terraform workspace, the provider waits and retries.