GitLab CI DNS Workflows
Practical GitLab CI patterns for DNSControl and Terraform DNS changes, including merge-request previews, protected deploys, scoped variables, and drift checks.
Answer snapshot
A safe GitLab CI DNS workflow validates and previews DNS changes in merge requests, then applies only from a protected branch or protected environment. Store DNScale credentials as protected and masked CI/CD variables, scope production variables to production jobs, and run scheduled drift checks so manual dashboard changes are detected instead of silently overwritten.
What you'll learn
- Build GitLab merge-request previews for DNSControl and Terraform
- Apply DNS changes only from protected branches and environments
- Store DNScale API keys using GitLab CI/CD variable controls
- Add scheduled drift checks and rollback paths
GitLab CI can run DNS changes safely when the pipeline has a hard boundary:
merge request = validate and preview
protected branch or environment = applyThis guide complements DNS in CI/CD Pipelines, GitHub Actions DNS Workflows, and DNS Automation.
For GitLab syntax details, keep the official GitLab CI/CD YAML reference, CI/CD variables documentation, and protected environments documentation nearby.
Repository Layout
Keep DNS easy to review.
dns/
dnsconfig.js
creds.example.json
zones/
example.com.js
terraform/
dns/
main.tf
variables.tf
versions.tfPick one source of truth per zone. Mixing Terraform, DNSControl, dashboard edits, and ad hoc scripts for the same record set creates drift.
GitLab Variables
Store DNScale credentials as GitLab CI/CD variables, not in .gitlab-ci.yml.
Recommended variables:
| Variable | Use |
|---|---|
DNSCALE_READ_TOKEN | Preview, plan, and drift checks where read-only access is enough |
DNSCALE_PRODUCTION_TOKEN | Apply jobs for production DNS |
DNSCALE_STAGING_TOKEN | Apply jobs for non-production DNS |
For production variables:
- mark them protected
- mark them masked if the value format allows it
- scope them to the production environment where possible
- avoid making them available to merge-request pipelines from untrusted sources
DNScale tokens should be zone-scoped where possible. A token for example.com should not be able to edit every zone in the account.
Pipeline Shape
Use stages:
stages:
- validate
- preview
- apply
- driftMerge requests run validate and preview. The default branch runs apply. A schedule runs drift.
DNSControl Merge-Request Preview
This job checks DNSControl config and prints a preview in merge-request pipelines.
dnscontrol:preview:
stage: preview
image: golang:1.25
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
changes:
- dns/**/*
- .gitlab-ci.yml
before_script:
- go install github.com/StackExchange/dnscontrol/v4@latest
script:
- cd dns
- dnscontrol check
- DNSCALE_API_KEY="$DNSCALE_READ_TOKEN" dnscontrol previewIf the provider requires write-capable credentials for preview, do not run this job in untrusted merge-request contexts.
DNSControl Apply
Apply only from the default branch and attach the job to a protected environment.
dnscontrol:apply:
stage: apply
image: golang:1.25
environment:
name: production
deployment_tier: production
rules:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
changes:
- dns/**/*
- .gitlab-ci.yml
before_script:
- go install github.com/StackExchange/dnscontrol/v4@latest
script:
- cd dns
- dnscontrol check
- DNSCALE_API_KEY="$DNSCALE_PRODUCTION_TOKEN" dnscontrol pushProtect the production environment in GitLab so only approved maintainers or release roles can deploy.
Terraform Merge-Request Plan
For Terraform-managed DNS:
terraform:dns:plan:
stage: preview
image: hashicorp/terraform:1.9
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
changes:
- terraform/dns/**/*
- .gitlab-ci.yml
variables:
TF_IN_AUTOMATION: "true"
script:
- cd terraform/dns
- terraform fmt -check
- terraform init -input=false
- terraform validate
- DNSCALE_API_KEY="$DNSCALE_READ_TOKEN" terraform plan -input=falseIf your Terraform state backend needs production credentials, decide whether merge-request plans are allowed to access that backend. If not, use a separate read-only plan path or restrict plans to trusted branches.
Terraform Apply
terraform:dns:apply:
stage: apply
image: hashicorp/terraform:1.9
environment:
name: production
deployment_tier: production
rules:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
changes:
- terraform/dns/**/*
- .gitlab-ci.yml
variables:
TF_IN_AUTOMATION: "true"
script:
- cd terraform/dns
- terraform init -input=false
- DNSCALE_API_KEY="$DNSCALE_PRODUCTION_TOKEN" terraform apply -input=false -auto-approveFor high-risk zones, avoid fully automatic apply. Use protected environments, required approvals, or a manual job:
when: manual
allow_failure: falseScheduled Drift Checks
GitLab schedules can run a non-mutating drift check.
DNSControl:
dnscontrol:drift:
stage: drift
image: golang:1.25
rules:
- if: '$CI_PIPELINE_SOURCE == "schedule"'
before_script:
- go install github.com/StackExchange/dnscontrol/v4@latest
script:
- cd dns
- DNSCALE_API_KEY="$DNSCALE_READ_TOKEN" dnscontrol previewTerraform:
terraform:dns:drift:
stage: drift
image: hashicorp/terraform:1.9
rules:
- if: '$CI_PIPELINE_SOURCE == "schedule"'
variables:
TF_IN_AUTOMATION: "true"
script:
- cd terraform/dns
- terraform init -input=false
- DNSCALE_API_KEY="$DNSCALE_READ_TOKEN" terraform plan -detailed-exitcode -input=falseWith terraform plan -detailed-exitcode, exit code 2 means changes are present. Treat that as a drift signal that needs review.
Rollback
Rollback should use the same path as the original change:
git revert <bad-commit>
git pushThen let the pipeline validate, preview, apply, and verify. For migrations, prepare the rollback commit before the change window begins.
Guardrails
Use these rules for production DNS:
- Merge requests preview DNS changes but do not mutate production.
- Production apply jobs run only from protected branches or protected environments.
- DNScale production tokens are protected, masked, and environment-scoped.
- Each token is scoped to the minimum set of zones.
- Drift jobs alert; they do not automatically overwrite manual changes.
- DS, DNSKEY, NS, MX, CAA, and apex changes require extra review.
Related Guides
Frequently asked questions
- Should GitLab CI apply DNS changes from merge requests?
- No. Merge requests should validate and preview. Apply jobs should run only after merge to a protected branch or through a protected production environment.
- Where should the DNScale API key live in GitLab?
- Store it as a GitLab CI/CD variable. Use protected and masked settings for production tokens, and scope variables to the environments that need them.
- Can I use the same pipeline for Terraform and DNSControl?
- Yes, but keep each tool's state and source of truth separate. Terraform is better when DNS is tied to infrastructure state. DNSControl is better for DNS-first, multi-provider, and zone-oriented workflows.
- How do I prevent forked or untrusted pipelines from seeing DNS secrets?
- Do not expose production variables to untrusted pipeline contexts. Use protected variables, protected branches/tags, environment-scoped variables, and manual approvals for production jobs.
- What should a DNS drift job do?
- Run a non-mutating preview or plan on a schedule and alert if live DNS differs from code. Do not automatically overwrite drift without review.
- How should rollback work?
- Rollback should be a normal revert or follow-up commit that restores previous DNS state through the same validate, preview, apply, and verify path.
Related guides
Automation
DNS Automation
A practical guide to automating DNS changes with APIs, CI/CD, DNS as code, scoped keys, previews, drift detection, and rollback workflows.
Automation
DNS as Code Best Practices
A practical guide to managing DNS as code with ownership, review, previews, drift detection, scoped credentials, and safe migration patterns.
Automation
DNS in CI/CD Pipelines
How to manage DNS changes through CI/CD with checks, previews, approvals, scoped secrets, drift detection, and safe rollback.
Automation
GitHub Actions DNS Workflows
Practical GitHub Actions patterns for DNSControl and Terraform DNS changes, including pull-request previews, protected applies, secrets, and drift checks.
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