From the makers of DNScale: PostScale -- reliable email delivery for developers. PostScale

    AutomationIntermediate

    Managing DNS with Terraform

    Manage DNS zones, records, and DNSSEC as code with the DNScale Terraform provider. Install the provider, create records, use CI/CD, and avoid DNS downtime.

    Answer snapshot

    A Terraform DNS provider lets you declare DNS zones and records in HCL, review changes in pull requests, and apply them through the same workflow as the rest of your infrastructure. The DNScale provider manages zones, records, DNSSEC keys, and read-only data sources. Use remote state, scoped API keys, plan reviews, and careful TTL changes so DNS automation stays predictable.

    What you'll learn

    • Install and configure the DNScale Terraform provider with secure credential management
    • Create DNS zones and common record types with verified HCL examples
    • Import existing DNScale zones and records into Terraform state safely
    • Review DNS changes through CI/CD without turning every pull request into a production mutation

    The DNScale Terraform provider lets platform and DevOps teams manage authoritative DNS zones, DNS records, and DNSSEC keys as code. Instead of changing production DNS by hand in a dashboard, you can commit HCL to Git, review the diff, run terraform plan, and apply the change through the same controlled workflow you use for infrastructure.

    This guide covers provider setup, record examples, imports, CI/CD, reusable modules, troubleshooting, and when Terraform is the right tool compared with the DNScale dashboard, API, or DNSControl.

    Quick Actions

    GoalStart here
    Install the providerAdd dnscaleou/dnscale to required_providers
    Authenticate safelyStore the API key in DNSCALE_API_KEY or a CI secret
    Create a zoneUse the dnscale_zone resource
    Add recordsUse dnscale_record with full record names and trailing dots
    Automate changesRun terraform plan on pull requests and apply from a protected branch

    Need an API key first? Create a DNScale account, then create a scoped key from the dashboard. For the raw API surface behind the provider, see the DNScale API docs.

    What Is a Terraform DNS Provider?

    A Terraform DNS provider lets you declare DNS resources in HCL instead of editing them manually. For DNScale, the provider maps DNS objects to Terraform resources:

    DNScale objectTerraform object
    DNS zonednscale_zone
    DNS recorddnscale_record
    DNSSEC keydnscale_dnssec_key
    Existing zone lookupdata "dnscale_zone" and data "dnscale_zones"
    Existing records lookupdata "dnscale_records"
    DNSSEC status lookupdata "dnscale_dnssec_status"

    Terraform is useful when DNS changes should be reviewed with code, tied to infrastructure resources, reused across environments, or deployed from CI/CD. A dashboard is still faster for a one-off test record or emergency change. A direct API script can be better for application-driven tasks such as short-lived tenant verification records.

    Why Manage DNS as Code?

    DNS controls traffic, certificates, email, and customer onboarding. Manual changes work until the team needs review, auditability, repeatability, and rollback.

    Problem with manual DNSDNS as code benefit
    Changes happen outside reviewPull requests and version control
    It is hard to know who changed whatGit history and Terraform state
    Repeated setup differs by environmentReusable modules and variables
    Human typo riskterraform plan before terraform apply
    Slow onboardingDNS configuration documents itself in code
    Manual drift after incidentsScheduled plans can detect drift

    For broader operating practices, read DNS as code best practices, DNS in CI/CD pipelines, and GitHub Actions DNS workflows.

    DNScale Terraform Provider Quickstart

    The DNScale provider is published on the Terraform Registry as dnscaleou/dnscale.

    1. Install Terraform.
    2. Create a DNScale API key.
    3. Add the provider to required_providers.
    4. Set credentials with DNSCALE_API_KEY or a sensitive Terraform variable.
    5. Create a zone.
    6. Add records.
    7. Run terraform init.
    8. Run terraform plan.
    9. Run terraform apply.
    Warning
    Do not commit API keys to Git. Use environment variables, CI secrets, Terraform Cloud variables, Vault, or your secret manager.
    terraform {
      required_providers {
        dnscale = {
          source  = "dnscaleou/dnscale"
          version = "~> 1.0"
        }
      }
    }
     
    provider "dnscale" {
      # Prefer DNSCALE_API_KEY in the environment.
      # api_url defaults to https://api.dnscale.eu
    }
    export DNSCALE_API_KEY="dns_xxx"
    terraform init
    terraform plan

    If you prefer explicit variables, keep the value sensitive and feed it from your secret manager:

    variable "dnscale_api_key" {
      description = "DNScale API key"
      type        = string
      sensitive   = true
    }
     
    provider "dnscale" {
      api_key = var.dnscale_api_key
    }

    Create a DNS Zone

    A DNS zone represents the domain managed by DNScale. The current provider schema requires name, region, and type.

    resource "dnscale_zone" "example" {
      name   = "example.com"
      region = "EU"
      type   = "master"
    }
     
    output "zone_id" {
      value = dnscale_zone.example.id
    }

    After the zone is created, delegate the domain at your registrar by pointing the parent-zone NS records to the DNScale nameservers shown in the dashboard or API. Keep delegation changes separate from record changes when possible; NS and DNSSEC mistakes can affect the whole domain.

    Manage Common DNS Records

    dnscale_record expects the full record name with a trailing dot, such as www.example.com. or example.com.. TTL is in seconds. Choose lower TTLs such as 300 for records that may change soon, and higher TTLs such as 3600 or 86400 for stable records. See DNS TTL best practices before migrations.

    A Record

    Use an A record to point a hostname to an IPv4 address.

    resource "dnscale_record" "www_a" {
      zone_id = dnscale_zone.example.id
      name    = "www.example.com."
      type    = "A"
      content = "192.0.2.10"
      ttl     = 300
    }

    AAAA Record

    Use an AAAA record to publish IPv6 alongside IPv4.

    resource "dnscale_record" "www_aaaa" {
      zone_id = dnscale_zone.example.id
      name    = "www.example.com."
      type    = "AAAA"
      content = "2001:db8::10"
      ttl     = 300
    }

    CNAME Record

    Use a CNAME record when a subdomain should follow another hostname. Avoid CNAMEs at names that also need MX, TXT, or other record data. For the common comparison, see CNAME vs A record.

    resource "dnscale_record" "docs" {
      zone_id = dnscale_zone.example.id
      name    = "docs.example.com."
      type    = "CNAME"
      content = "example.gitbook.io."
      ttl     = 3600
    }

    MX Record

    Use MX records to route inbound email. DNScale uses the separate priority field for MX priority.

    resource "dnscale_record" "mx_primary" {
      zone_id  = dnscale_zone.example.id
      name     = "example.com."
      type     = "MX"
      content  = "mail.example.com."
      priority = 10
      ttl      = 3600
    }

    TXT Record

    Use TXT records for SPF, DKIM, DMARC, ownership verification, and other text values.

    resource "dnscale_record" "spf" {
      zone_id = dnscale_zone.example.id
      name    = "example.com."
      type    = "TXT"
      content = "v=spf1 include:_spf.example.com -all"
      ttl     = 3600
    }

    For email authentication records, also see SPF records explained, DKIM explained, and DMARC explained.

    CAA Record

    Use CAA records to control which certificate authorities may issue certificates for a domain.

    resource "dnscale_record" "caa" {
      zone_id = dnscale_zone.example.id
      name    = "example.com."
      type    = "CAA"
      content = "0 issue \"letsencrypt.org\""
      ttl     = 3600
    }

    SRV Record

    Use SRV records for service discovery with priority, weight, port, and target in the content field.

    resource "dnscale_record" "sip" {
      zone_id  = dnscale_zone.example.id
      name     = "_sip._tcp.example.com."
      type     = "SRV"
      content  = "10 5 5060 sip.example.com."
      priority = 0
      ttl      = 3600
    }

    ALIAS, HTTPS, SVCB, TLSA, SSHFP, and PTR

    The provider also accepts advanced record types documented in the DNS record types reference, including ALIAS, HTTPS, SVCB, TLSA, SSHFP, and PTR. Use these only when the consuming service expects them:

    Terraform DNS Record Examples Table

    TaskRecord typeTerraform resourceRelated DNScale guide
    Point a hostname to IPv4Adnscale_recordA record guide
    Point a hostname to IPv6AAAAdnscale_recordAAAA record guide
    Alias a subdomainCNAMEdnscale_recordCNAME guide
    Route inbound emailMXdnscale_record with priorityMX record guide
    Publish SPF, DKIM, DMARC, or verification textTXTdnscale_recordTXT record guide
    Restrict certificate issuersCAAdnscale_recordCAA record guide
    Publish service host and portSRVdnscale_record with prioritySRV record guide
    Use apex hostname aliasingALIASdnscale_recordALIAS record guide

    Manage DNSSEC With Terraform

    The DNScale provider exposes dnscale_dnssec_key for KSK and ZSK resources. Use uppercase key types and algorithm names as shown in the provider docs.

    resource "dnscale_dnssec_key" "ksk" {
      zone_id   = dnscale_zone.example.id
      key_type  = "KSK"
      algorithm = "ECDSAP256SHA256"
      active    = true
      published = true
    }
     
    resource "dnscale_dnssec_key" "zsk" {
      zone_id   = dnscale_zone.example.id
      key_type  = "ZSK"
      algorithm = "ECDSAP256SHA256"
      active    = true
      published = true
    }
     
    output "ds_records" {
      value = dnscale_dnssec_key.ksk.ds
    }

    DNSSEC has an extra registrar step: the DS record must be published at the parent zone. Do not change DNSSEC keys, DS records, or nameservers without a rollback plan. For the operational sequence, read DNSSEC setup for DNScale and DNSSEC key management.

    Import Existing DNS Into Terraform

    Import is useful when a zone already exists in DNScale and you want Terraform to take ownership without deleting and recreating records.

    Start with an inventory:

    1. Export or list the existing zone and record IDs from the dashboard or API.
    2. Recreate the intended HCL using full record names with trailing dots.
    3. Import the existing resources into state.
    4. Run terraform plan and fix HCL until the plan shows no unwanted change.
    5. Only then allow Terraform to apply changes.
    # Import a zone by UUID.
    terraform import dnscale_zone.example <zone-id>
     
    # Import a record by zone ID and record ID.
    terraform import dnscale_record.www <zone-id>/<record-id>
     
    # Import a DNSSEC key by zone ID and key ID.
    terraform import dnscale_dnssec_key.ksk <zone-id>/<key-id>

    Terraform import adopts resources one at a time; it does not automatically convert an entire BIND file or another provider's zone into HCL. For cross-provider migrations, first use zone import methods, then adopt the resulting DNScale records into Terraform if Terraform will become the source of truth.

    You can also use data sources to inspect what exists:

    data "dnscale_records" "all" {
      zone_id = dnscale_zone.example.id
    }
     
    output "a_records" {
      value = [for r in data.dnscale_records.all.records : r if r.type == "A"]
    }

    How To Avoid DNS Downtime With Terraform

    Lower TTLs Before High-Risk Changes

    Lower TTLs before migrations, wait for the old TTL to expire, then make the cutover. Restore higher TTLs after the new state is stable. For the full pattern, see DNS TTL best practices.

    Review Plan Output Before Applying

    Read every DNS diff before terraform apply, especially deletes. A deleted MX record can stop inbound email; a bad CAA record can block certificate issuance; a bad DS record can cause DNSSEC SERVFAIL.

    Change Nameservers and DNSSEC Separately

    Do not bundle NS delegation, DS records, DNSSEC keys, and application record changes in one large pull request. Smaller changes make failures easier to isolate.

    Verify From Authoritative and Recursive Resolvers

    After applying, check what the authoritative nameservers serve and what public resolvers cache. Use the DNS propagation checker, DNS lookup tool, zone health check, and DNSSEC chain validator where relevant.

    Keep Break-Glass Access

    Terraform should be the routine path, not the only path. Keep emergency dashboard/API access available, then backfill emergency changes into HCL immediately after the incident.

    Keep Public DNS Independent

    For production domains, avoid making authoritative DNS depend on the same compute cloud it routes to. For architecture trade-offs, read DNS for cloud infrastructure and multi-provider DNS deployment.

    Terraform in CI/CD

    A safe DNS pipeline separates preview from apply:

    StageRuns whenCommand
    Format and validatePull requestterraform fmt -check and terraform validate
    PreviewPull requestterraform plan -input=false
    ApplyProtected branch onlyterraform apply -input=false
    Drift checkScheduledterraform plan -detailed-exitcode

    Minimal GitHub Actions example:

    name: terraform-dns
     
    on:
      pull_request:
        paths: ["terraform/dns/**"]
      push:
        branches: ["main"]
        paths: ["terraform/dns/**"]
     
    jobs:
      plan:
        runs-on: ubuntu-latest
        defaults:
          run:
            working-directory: terraform/dns
        steps:
          - uses: actions/checkout@v4
          - uses: hashicorp/setup-terraform@v3
          - run: terraform fmt -check
          - run: terraform init -input=false
          - run: terraform validate
          - run: terraform plan -input=false
            env:
              DNSCALE_API_KEY: ${{ secrets.DNSCALE_READ_TOKEN }}
     
      apply:
        if: github.event_name == 'push' && github.ref == 'refs/heads/main'
        runs-on: ubuntu-latest
        environment: production
        defaults:
          run:
            working-directory: terraform/dns
        steps:
          - uses: actions/checkout@v4
          - uses: hashicorp/setup-terraform@v3
          - run: terraform init -input=false
          - run: terraform apply -auto-approve -input=false
            env:
              DNSCALE_API_KEY: ${{ secrets.DNSCALE_PRODUCTION_TOKEN }}

    Use remote state and locking for teams. Keep production write credentials out of untrusted pull-request contexts. For more patterns, see DNS in CI/CD pipelines and GitHub Actions DNS workflows.

    Reusable DNS Modules

    Modules help when many zones share the same shape, such as website records, customer subdomains, or standard email records. Keep modules transparent enough that reviewers can still see what record data will change.

    # modules/website-records/main.tf
    variable "zone_id" {
      type = string
    }
     
    variable "domain" {
      type = string
    }
     
    variable "apex_ipv4" {
      type = string
    }
     
    resource "dnscale_record" "apex" {
      zone_id = var.zone_id
      name    = "${var.domain}."
      type    = "A"
      content = var.apex_ipv4
      ttl     = 300
    }
     
    resource "dnscale_record" "www" {
      zone_id = var.zone_id
      name    = "www.${var.domain}."
      type    = "CNAME"
      content = "${var.domain}."
      ttl     = 300
    }

    Good module candidates:

    • Website records: apex A/AAAA plus www CNAME.
    • Email records: MX, SPF, DKIM, DMARC, and optional MTA-STS/TLS-RPT.
    • SaaS tenant records: customer CNAME plus verification TXT.
    • Environment records: staging and production subdomains with separate variables.

    Avoid hiding high-risk records such as NS, DS, DNSKEY, MX, and CAA behind overly clever abstractions.

    Terraform vs Dashboard vs API vs DNSControl

    MethodBest forTrade-offs
    DNScale dashboardFast manual changes, exploration, emergency fixesLess review and version-control discipline
    DNScale APICustom automation and application workflowsYou maintain validation, retries, diffing, and rollback
    Terraform providerInfrastructure-as-code teams using HCL, remote state, and PR reviewsRequires state management and plan/apply discipline
    DNSControlDNS-specific workflows, readable zone files, multi-provider DNSUses a separate JavaScript-based workflow

    Terraform and DNSControl can coexist, but avoid having two systems manage the same zone or record set. Pick one source of truth per zone. For DNSControl setup, read the DNScale DNSControl guide.

    Troubleshooting Terraform DNS Changes

    ProblemLikely causeFix
    Provider cannot authenticateMissing, expired, or wrongly scoped API keyCheck DNSCALE_API_KEY, CI secrets, and API key scopes in authentication docs
    Zone creation failsMissing required region or type, or unsupported value casingUse region = "EU" or "US" and type = "master" or "slave"
    Record already existsResource is not imported or another writer created the recordImport the record or remove the duplicate writer
    Plan wants to recreate recordsHCL does not match provider-normalized names or IDsUse full record names with trailing dots and compare with data "dnscale_records"
    DNS change applied but users still see old answerTTL and recursive resolver cachingCheck authoritative answers and public caches with the DNS propagation checker
    CNAME conflicts with other recordsCNAME cannot coexist with other record data at the same nameUse A/AAAA/ALIAS or remove conflicting records; see CNAME vs A record
    MX email is not routingPriority, target hostname, or target address records are wrongVerify MX records and the A/AAAA records for the mail host
    Certificate issuance failsCAA record is missing the right CA or too restrictiveCheck CAA record configuration
    DNSSEC validation failsDS/DNSKEY mismatch or unsafe key timingReview DNSSEC setup and test with the DNSSEC chain validator
    ResourceWhy it matters
    DNS as code best practicesOperating model for reviewable DNS
    DNS in CI/CD pipelinesValidation, preview, apply, and drift detection
    GitHub Actions DNS workflowsConcrete GitHub Actions examples
    DNS record typesChoose the right record type before writing HCL
    DNS TTL best practicesPlan migrations and cache behavior
    Zone import methodsMove existing DNS into DNScale before adopting Terraform
    DNScale API records docsUnderstand the record API behind the provider
    DNS propagation checkerVerify changes across authoritative and recursive resolvers

    Manage DNS Records as Code With DNScale

    DNScale gives you authoritative DNS that can be managed through the dashboard, API, Terraform provider, and DNSControl. Start with a scoped API key, put your DNS configuration in reviewable code, and use tools like DNS lookup, propagation checks, and zone health checks to verify changes after apply.

    Frequently asked questions

    What is a Terraform DNS provider?
    A Terraform DNS provider is a plugin that maps DNS provider API objects, such as zones and records, into Terraform resources and data sources so DNS can be reviewed, planned, applied, and tracked in state.
    Can Terraform manage DNS records?
    Yes. With the DNScale provider, Terraform can manage DNS zones, A, AAAA, CNAME, MX, TXT, NS, SOA, SRV, CAA, PTR, ALIAS, TLSA, SSHFP, HTTPS, and SVCB records.
    How do I use the DNScale Terraform provider?
    Add source dnscaleou/dnscale to required_providers, set DNSCALE_API_KEY as an environment variable or pass a sensitive api_key variable, run terraform init, declare dnscale_zone and dnscale_record resources, then review terraform plan before applying.
    How should I store my DNScale API key for Terraform?
    Do not commit API keys. Use DNSCALE_API_KEY in your shell, CI secrets, Terraform Cloud variables, or a secret manager. Prefer zone-scoped API keys for automation so a leaked token cannot edit unrelated zones.
    Can I import an existing DNS zone into Terraform?
    Yes, existing DNScale resources can be imported one resource at a time. Zones use terraform import dnscale_zone.example <zone-id>; records use terraform import dnscale_record.www <zone-id>/<record-id>; DNSSEC keys use terraform import dnscale_dnssec_key.ksk <zone-id>/<key-id>.
    How do I avoid downtime when changing DNS with Terraform?
    Lower TTLs before migrations, review plan output, avoid combining delegation and record changes in one pull request, keep rollback records ready, and verify results with authoritative lookups and public resolvers.
    Can Terraform manage DNSSEC with DNScale?
    The provider includes dnscale_dnssec_key for KSK and ZSK management plus a dnscale_dnssec_status data source. Treat registrar-side DS publication as a separate operational step unless your registrar is also managed in Terraform.
    What is the difference between Terraform and DNSControl for DNS?
    Terraform is best when DNS belongs next to broader infrastructure state and HCL modules. DNSControl is best when DNS itself is the primary workflow, especially across many zones or multiple DNS providers.
    Should DNS be managed in the same Terraform state as cloud infrastructure?
    Sometimes, but keep the blast radius in mind. Shared state is useful when records reference load balancers or static IPs directly. Separate DNS state is safer for long-lived zones, delegation, email, and records that must survive compute-stack rebuilds.

    Related guides

    Ready to manage your DNS with confidence?

    DNScale provides anycast DNS hosting with a global network, real-time analytics, and an easy-to-use API.

    Start free