Technitium DNS Server is an open-source, cross-platform, self-hosted DNS server with a full-featured web console. It supports authoritative zones, recursive resolution, DNSSEC, DNS-over-HTTPS/TLS, blocking, and much more — making it an excellent choice for production DNS infrastructure.
This provider enables you to manage Technitium DNS Server infrastructure entirely as code through Terraform. Define zones, records, TSIG keys, DNSSEC configuration, catalog zone membership, and server-wide settings in declarative HCL, then plan, review, and apply changes with the same workflow you use for every other piece of your infrastructure.
What sets this provider apart is its embedded DISA STIG
compliance validation with full NIST SP 800-53 Rev. 5
traceability. Twenty-eight DNS security requirements are evaluated at terraform validate
and terraform plan time, catching misconfigurations before they reach your DNS server.
Supported STIGs:
| STIG | Version | Library Release Date |
|---|---|---|
| BIND 9.x STIG | V3R3 | 2026-07-01 |
| Windows Server 2022 DNS STIG | V2R5 | 2026-07-01 |
Dates are the release dates published in the DISA STIG Public Library archive metadata at the time of the corresponding provider release.
Already managing infrastructure as code? Define your DNS zones, records, DNSSEC,
TSIG keys, and server-wide settings alongside the rest of your stack — Kubernetes manifests,
cloud resources, container deployments — in the same terraform apply lifecycle.
New to infrastructure as code? The embedded STIG validators catch DNS misconfigurations
at terraform plan time, before they reach your server. Each finding includes the STIG
Rule ID, severity, and mapped NIST SP 800-53 control — you see the problem with the fix
attached, not after the next audit.
Running multiple Technitium nodes? The technitium_catalog_membership resource
(new in v1.2) declaratively manages RFC 9432
catalog zone membership so secondary name servers automatically provision member zones —
no per-secondary manual configuration.
- DNS zone management (Primary, Secondary, Stub, Forwarder)
- DNS record management (A, AAAA, CNAME, MX, TXT, SRV, PTR, NS, CAA) with multi-record support for round-robin, multiple MX exchanges, and other multi-value configurations
- DNSSEC signing configuration
- TSIG key management for authenticated zone transfers
- Catalog zone membership (RFC 9432) for multi-server deployments
- Server-wide DNS settings
- Domain blocking and allowing
- Built-in DISA STIG compliance validation (28 DNS security requirements)
- NIST SP 800-53 Rev. 5 control traceability and baseline categorization
- NSS/CNSSI 1253 support for classified environments
- TLS configuration with custom CA support and environment variable fallbacks
- Client-side DNS record input validation
Running Technitium on your home network over HTTP, just want IaC-managed records?
Start here. Findings show in plan output but do not block apply until you decide
to harden:
terraform {
required_providers {
technitium = {
source = "darkhonor/technitium"
version = "~> 1.3"
}
}
}
provider "technitium" {
server_url = "http://192.168.1.10:5380"
api_token = var.technitium_api_token
stig_compliance {
enabled = true
enforcement = "warn" # findings appear in plan output but do not block apply
}
}
resource "technitium_zone" "homelab" {
name = "home.lan"
type = "Primary"
}
resource "technitium_record" "nas" {
zone = technitium_zone.homelab.name
name = "nas.home.lan"
type = "A"
value = "192.168.1.50"
}When you're ready to harden — add notify, allow_transfer, DNSSEC, switch to
HTTPS, and drop the enforcement = "warn" line. The findings you saw earlier
become the checklist.
HTTPS-enabled Technitium, strict STIG enforcement, custom CA for an internal PKI:
provider "technitium" {
server_url = "https://dns.example.com"
api_token = var.technitium_api_token
ca_cert_file = "/etc/ssl/certs/internal-ca.pem"
tls_server_name = "dns.example.com"
tls_min_version = "1.3"
# strict mode is the default — included here for clarity
stig_compliance {
enabled = true
enforcement = "strict"
}
}
resource "technitium_zone" "example" {
name = "example.com"
type = "Primary"
notify = ["10.0.0.2"]
allow_transfer = ["10.0.0.0/8"]
dnssec {
enabled = true
algorithm = "ECDSA"
curve = "P384"
nx_proof = "NSEC3"
}
}
resource "technitium_record" "web" {
zone = technitium_zone.example.name
name = "www.example.com"
type = "A"
value = "192.168.1.100"
}Multiple records at the same name and type are fully supported — set overwrite = false
to manage individual records within an RRset:
resource "technitium_record" "web1" {
zone = technitium_zone.example.name
name = "www.example.com"
type = "A"
value = "192.168.1.100"
overwrite = false
}
resource "technitium_record" "web2" {
zone = technitium_zone.example.name
name = "www.example.com"
type = "A"
value = "192.168.1.101"
overwrite = false
}The provider can also be configured using environment variables:
export TECHNITIUM_SERVER_URL="https://dns.example.com"
export TECHNITIUM_API_TOKEN="your-api-token"Both providers can add DNS records to Technitium, but they take fundamentally different
paths. hashicorp/dns speaks generic RFC 2136
dynamic updates over TSIG — the same protocol Bind 9 uses — and works against any
DNS server that supports it. darkhonor/technitium talks directly to Technitium's
native HTTP API and exposes the full administrative surface, not just the records subset.
| Capability | hashicorp/dns (v3.6.1) |
darkhonor/technitium |
|---|---|---|
| Manage DNS records | yes (8 *_record* resources) |
yes (technitium_record) |
| Create + configure zones | no (zones must exist on the DNS server first) | yes (technitium_zone) |
| DNSSEC configuration | no | yes (algorithm, curve, NSEC3) |
| TSIG key lifecycle on the server | no (server-side key configured manually) | yes (technitium_tsig_key) |
| Catalog zone membership (RFC 9432) | no | yes (technitium_catalog_membership) |
| Server-wide settings (blocking, forwarding) | no | yes (technitium_server_settings) |
| Authentication | TSIG (RFC 2845) shared secret, OR GSS-TSIG (RFC 3645) for Kerberos / Active Directory | Per-user API token (revocable, scoped) |
| Embedded STIG compliance validation | no | yes (28 DNS security requirements) |
| Provider-to-server transport | UDP/TCP on port 53 | HTTPS (REST API) |
Where hashicorp/dns is the better fit: Active-Directory-integrated environments
where GSS-TSIG / Kerberos authentication is the natural choice, or mixed-DNS-server
environments where standard RFC 2136 compatibility across multiple vendors matters
more than Technitium-specific features. This provider does not implement Kerberos
authentication.
Where this provider is the better fit: Technitium-only deployments where you want end-to-end management — zones, DNSSEC posture, TSIG keys, catalog membership, server settings, blocking, and the records themselves — in one declarative configuration, with STIG validation built in.
This provider embeds 28 DNS security requirements derived from DISA STIGs and validates
them at terraform validate and terraform plan time — no external tools or post-hoc
scanning required. Every finding includes the STIG Rule ID, severity, and mapped
NIST SP 800-53 Rev. 5 control for full audit traceability.
Three enforcement modes are available:
| Mode | Behavior |
|---|---|
| strict (default) | Errors block terraform apply |
| warn | Warnings appear in plan output but do not block |
| silent | All STIG diagnostics suppressed |
If you do not need compliance enforcement on a specific deployment, set
enforcement = "warn" to see findings without blocking, or enforcement = "silent"
to suppress them entirely. The validators run only when stig_compliance.enabled = true.
For classified environments, NSS mode maps controls to CNSSI 1253 baselines (Low, Moderate, High) and enforces only the requirements applicable to the selected categorization level.
Upgrading from v1.1.x? Two STIG validators (DNS-REQ-004 zone-transfer ACL, DNS-REQ-016 notify addresses) were silently no-op in v1.0 and v1.1 and now properly enforce. Strict-mode users running existing HCL without
notifyorallow_transferpopulated will see new findings onterraform plan. See the CHANGELOG Upgrade Notes for remediation paths.
For full details, see the STIG Compliance Guide and the DISA STIG Library.
| Requirement | Version |
|---|---|
| Terraform | >= 1.0 |
| Go (for building) | >= 1.27.1 |
| Technitium DNS Server | >= 15.0 (15.5.1 or later recommended); older servers need legacy_token_auth = true |
The acceptance suite runs against Technitium 15.5.1. Servers older than 15.0 are not covered by it.
Upgrading to v1.3? Check these before upgrading:
- Technitium older than 15.0: the provider now sends the API token as an
Authorization: Bearerheader, which older servers ignore. Setlegacy_token_auth = truebefore upgrading the provider, or upgrade the server first.- Two
FWDrecords in one zone with the samevalueandprotocol: Technitium cannot tell them apart, so the provider now refuses to create such a pair and refuses to destroy or update either record of an existing one. Rebuild the pair so the records differ byvalueorprotocol.- A
server_urlthat redirects, or a proxy that blocksPOST: the provider follows a redirect only within the same scheme, host, and port, and sends writes asPOSTform bodies. Setserver_urlto the final address; see Reverse Proxies and Load Balancers.stig_compliancewithstrictenforcement (the default): unsigning a zone now requiresdnssec.change_acknowledgment = "unsigned".- Upgrading Technitium to 15.5 or later: a forwarder zone whose forwarder has
dnssec_validation = falsebecomes a Negative Trust Anchor (DNSSEC validation off for that namespace), and the record's comment is returned to any client that queries it.See Upgrading to v1.3 for what to check, how to rebuild forwarder pairs, and the recommended upgrade order.
terraform {
required_providers {
technitium = {
source = "darkhonor/technitium"
version = "~> 1.3"
}
}
}Then run terraform init.
Clone the repository and install the provider binary into your local plugin directory:
git clone https://github.com/darkhonor/terraform-provider-technitium.git
cd terraform-provider-technitium
make install- Terraform Registry Documentation
- STIG Compliance Guide
- Upgrading to v1.3
- Reverse Proxies and Load Balancers
- Changelog
- Security policy
git clone https://github.com/darkhonor/terraform-provider-technitium.git
cd terraform-provider-technitium
make buildRun unit tests:
make testRun the full acceptance test suite (requires Docker):
make testacc-upThis starts a Technitium DNS Server container, provisions a fresh API token, and runs every acceptance test. The container stays running so you can iterate. Tear it down when finished:
make testacc-downNote: Acceptance tests require a running Technitium DNS Server instance. The
make testacc-uptarget handles the full lifecycle: runs a preflight ownership check on./.testdata/, creates the bind-mount data directory with host-user ownership, starts the container as a non-root user (per issue #36), provisions a fresh API token, and runs every acceptance test. Unit tests (make test) do not require Docker and run entirely offline.Invoking
docker compose -f docker-compose.test.yml up -ddirectly is not supported. The compose file'suser:directive expectsHOST_UIDandHOST_GIDenvironment variables exported by the make target, and the bind-mount source directory must exist with the host user's ownership before container start. Bypassingmakewill silently fall back to1000:1000and may produce permission errors on any host where the user's UID/GID differs.
The default make testacc-up runs the Technitium container with HTTP only on port 5380,
which is sufficient for most resource and data-source tests but blocks the NSS-mode and
strict STIG-mode test families that require encrypted transport (DNS-REQ-028 / NIST SC-8).
The parallel testacc-up-tls target boots an HTTPS-enabled container and runs the full
test suite against it:
make testacc-up-tls # generate fresh CA + server cert, boot HTTPS container, run all tests
make testacc-down-tls # tear down the HTTPS container when finishedThe TLS variant generates a fresh ECDSA P-384 self-signed CA and server certificate into
./testdata/tls/ (gitignored), packages the server credentials as a PKCS#12 bundle,
mounts them into the Technitium container at /etc/dns/tls/server.pfx, and exposes the
admin web service on 127.0.0.1:5443 over HTTPS. The provider trusts the test CA via the
TECHNITIUM_CACERT environment variable. No private key material is ever committed.
A few test helpers and direct-API helpers across the suite still hardcode the HTTP URL where they exist purely to test HTTP-failure or skip-TLS-verify behavior; those tests intentionally do not pick up the TLS overrides. The TLS path's primary value is unblocking the NSS-mode and STIG-strict test families that cannot run under HTTP at all.
The TLS target sources DNS_ADMIN_PASSWORD from .env.test (falling back to admin to
match .env.test.example). It does not require any production credential.
Credential handling: the make targets read
DNS_ADMIN_PASSWORDfrom.env.testinto a shell variable and pipe it toscripts/test-token-bootstrap.shon stdin via a shell-builtinprintf. The script reads the password from stdin into a local shell variable, never sees it via argv or env, URL-encodes it through a python helper that also reads from stdin, and sends the form body to curl via--data @-on a bash heredoc. The credential value therefore does not appear in/proc/PID/cmdline(ps -ef) or/proc/PID/environ(ps eww) of any process spawned during token provisioning. Resolved in v1.2.0 (#35).
CI runs testacc-up-tls automatically on every pull request.
Build with BoringCrypto for FIPS 140-2 compliance:
make build-fipsFIPS-mode tests are also available:
make test-fipsRegistry-format documentation is generated with tfplugindocs:
make docsmake lintMPL-2.0. See LICENSE.