Skip to main content

cloider_dns_record resource (Terraform)

The cloider_dns_record resource manages a DNS record set on a custom cloider_domain: every value of one type at one name, such as both MX servers of example.com, or every TXT value at example.com. Cloider's nameservers answer with exactly these records, so this is how a custom domain's website, mail and verification records are served.

At a glance​

Required argumentsdomain, type, values, ttl
Changes in placetype, name, values, ttl
Changes that replace the recorddomain
Record typesA, AAAA, CNAME, ALIAS, MX, TXT, NS, CAA, HTTPS, SPF, SRV, PTR
TTL60 to 172800 seconds
Import IDThe record's numeric id, such as 48213
API/api/domains/<domain>/dns-records, /api/dns-records/<id>
CLI equivalentcloider dns
One resource per type and name

Cloider keeps one record per type and name, holding all of its values. Put every value of, say, the TXT records at the apex into one resource's values. Two resources with the same domain, type and name would overwrite each other.

Example usage​

A record at the apex and a CNAME for www​

main.tf
resource "cloider_domain" "example" {
name = "example.com"
}

# The apex: name defaults to "", the domain itself. It takes over the ALIAS
# record the domain was added with
resource "cloider_dns_record" "apex" {
domain = cloider_domain.example.name
type = "A"
values = ["203.0.113.80"]
ttl = 300
}

resource "cloider_dns_record" "www" {
domain = cloider_domain.example.name
type = "CNAME"
name = "www"
values = ["acme-web.cloider.app."]
ttl = 3600
}

A CNAME takes exactly one value, and can't be used at the apex. To serve a host name from Cloider, point it at a free subdomain you hold with a CNAME. The apex already points at Cloider through the ALIAS record the domain came with, so add an apex A record (as above) or ALIAS record only when the apex is served somewhere else. See Add a custom domain.

Mail: MX, SPF, DKIM and DMARC​

mail.tf
resource "cloider_dns_record" "mx" {
domain = "example.com"
type = "MX"
values = ["10 mx1.mail.example.net.", "20 mx2.mail.example.net."]
ttl = 3600
}

# Each TXT value is a TXT record of its own, so the SPF policy and a
# verification token at the apex go in one resource
resource "cloider_dns_record" "apex_txt" {
domain = "example.com"
type = "TXT"
values = [
"v=spf1 include:mail.example.net ~all",
"google-site-verification=rXOxyZounnZasA8Z7oaD3c14JdjS9aKSWvsR1EbUSIQ",
]
ttl = 3600
}

# A value over 255 characters, such as a DKIM key, is fine as one value
resource "cloider_dns_record" "dkim" {
domain = "example.com"
type = "TXT"
name = "mail._domainkey"
values = ["v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu5..."]
ttl = 3600
}

resource "cloider_dns_record" "dmarc" {
domain = "example.com"
type = "TXT"
name = "_dmarc"
values = ["v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com"]
ttl = 3600
}

Use your mail provider's exact values. See Email DNS records.

SRV record​

main.tf
# Each value is: priority weight port target
resource "cloider_dns_record" "sip" {
domain = "example.com"
type = "SRV"
name = "_sip._tcp"
values = ["10 60 5060 sip1.example.com.", "20 40 5060 sip2.example.com."]
ttl = 3600
}

CAA record​

main.tf
# Which certificate authorities may issue certificates for the domain.
# Cloider's HTTPS certificates come from Let's Encrypt, so keep it allowed.
resource "cloider_dns_record" "caa" {
domain = "example.com"
type = "CAA"
values = [
"0 issue \"letsencrypt.org\"",
"0 iodef \"mailto:security@example.com\"",
]
ttl = 3600
}

Wildcard​

main.tf
# Answers for any name under example.com that has no record of its own
resource "cloider_dns_record" "wildcard" {
domain = "example.com"
type = "A"
name = "*"
values = ["203.0.113.10"]
ttl = 300
}

Many records from a map with for_each​

dns.tf
locals {
records = {
"www CNAME" = { type = "CNAME", name = "www", values = ["acme-web.cloider.app."] }
"shop CNAME" = { type = "CNAME", name = "shop", values = ["acme-shop.cloider.app."] }
"@ MX" = { type = "MX", name = "", values = ["10 mx1.mail.example.net."] }
}
}

resource "cloider_dns_record" "this" {
for_each = local.records

domain = cloider_domain.example.name
type = each.value.type
name = each.value.name
values = each.value.values
ttl = 3600
}

Key the map by name and type, so each key is one record set.

Argument reference​

ArgumentTypeRequiredDefaultChanging itDescription
domainStringYesReplaces the recordThe custom domain the record belongs to, such as example.com. Free subdomains under Cloider's roots don't take records
typeStringYesIn placeA, AAAA, CNAME, ALIAS, MX, TXT, NS, CAA, HTTPS, SPF, SRV or PTR (upper case)
nameStringNo"" (the domain itself)In placeThe name under the domain, such as www, _dmarc or *. Write it relative to the domain: www, not www.example.com. Leave it out for the domain itself: @ is refused
valuesList of StringYesIn placeThe record's values, at least one. Each value is one line, without leading or trailing spaces. Each TXT value is a TXT record of its own. A CNAME or ALIAS takes one
ttlNumberYesIn placeSeconds resolvers may cache the record, 60 to 172800

Value formats​

TypeValue formatExample
AIPv4 address203.0.113.80
AAAAIPv6 address2001:db8::80
CNAMEHost name, ending in a dotacme-web.cloider.app.
ALIASHost name, also allowed at the apexmyapp.herokuapp.com
MXPriority and mail server10 mx1.mail.example.net.
TXTText, without surrounding quotesv=spf1 include:mail.example.net ~all
SRVPriority, weight, port and target10 60 5060 sip1.example.com.
CAAFlags, tag and value0 issue "letsencrypt.org"

See DNS records for every type, including NS, HTTPS, SPF and PTR.

Attribute reference​

AttributeTypeDescription
idStringThe record's numeric id, as a string, such as "48213"

Behavior notes​

  • Values are compared as written. Cloider trims each value and drops empty ones, so the provider refuses values with leading or trailing spaces or line breaks at plan time (must be one line, without leading or trailing spaces). Otherwise every plan would show a change.
  • Changing type or name updates the same record in place, rather than creating a new one.
  • The apex ALIAS record. A custom domain comes with an ALIAS record for the domain itself that points at cloider.app, and at the app's free subdomain once a target routes the domain to an app. While it still points at Cloider, a record of type A, AAAA or ALIAS without a name takes it over instead of failing next to it.
  • Deleting the domain deletes its records too.
  • Deleted outside Terraform. The next refresh removes the record from state and the plan offers to create it again.

Import​

Import a record by its numeric id. cloider dns list <domain> -o wide shows the ids:

cloider dns list example.com -o wide
Output
ID TYPE NAME VALUE TTL
48213 A @ 203.0.113.80 300
48214 CNAME www acme-web.cloider.app. 3600
48215 MX @ 10 mx1.mail.example.net. 3600

With an import block:

imports.tf
import {
to = cloider_dns_record.apex
id = "48213"
}

import {
to = cloider_dns_record.www
id = "48214"
}

With the terraform import command:

terraform import cloider_dns_record.apex 48213

An id that isn't a number fails with Invalid DNS record id: A DNS record's id is a number, see 'cloider dns list <domain>'. A record with several values (several MX servers, say) is one record with one id. Import the domain itself too, with cloider_domain.

Frequently asked questions

How do I add a DNS record to a Cloider domain with Terraform?

Add a cloider_dns_record with domain, type, values and ttl, and name for anything other than the domain itself. The domain must be a custom domain added with cloider_domain or imported.

How do I add several TXT records at the same name?

List them all in one cloider_dns_record's values. Each TXT value is served as a TXT record of its own. Two resources with the same domain, type and name would overwrite each other.

Can I add DNS records to a free cloider.app subdomain?

No. Free subdomains are answered by Cloider and don't take records. DNS records are for custom domains only.

What TTL can a Cloider DNS record have?

From 60 to 172800 seconds. ttl is required in Terraform. 300 is a good value for records you may change soon, 3600 for stable ones.

What is the import ID of a cloider_dns_record?

The record's numeric id, shown in the ID column of cloider dns list <domain> -o wide. For example terraform import cloider_dns_record.apex 48213.