External providers¶
The optional dns_external submodule connects local zones and records
to remote DNS provider accounts (ClouDNS, Route 53, Cloudflare, …) so
you can import zones from the provider into Drupal or push local
changes back out.
dns_external is the framework: the plugin manager, the binding
entity, the importer, and the pusher. Each concrete provider ships as
its own module that registers a Provider plugin against this
framework. ClouDNS's integration is dns_cloudns; others (Route 53,
Cloudflare) are similarly named. Enable the framework first, then the
provider modules you actually use.
Install¶
The framework has a hard dependency on the
Key module. The dns module
itself doesn't pull Key in — sites that don't need
dns_external shouldn't carry the cost — so you have to require
it explicitly before enabling the submodule:
composer require drupal/key
drush en dns_external
drush en dns_cloudns # or whichever provider module you need
Provider plugins store secret credential material (passwords, API tokens) as references to Key entities, never as raw secrets in module config. Non-secret identifiers (account ids, usernames, endpoint URLs) live in plain config; wrapping them in Keys would add friction without protecting anything.
Concepts¶
| Term | What it is |
|---|---|
| Provider plugin | The integration class for one DNS service (ClouDNS, Route 53). |
| Provider configuration | A Drupal config entity holding one provider account (a label, the plugin id, and plugin-specific settings — secret credentials referenced by Key id, identifiers in plain config). One per account; you can run two ClouDNS accounts and a Route 53 account on the same site. |
| External binding | A content entity that ties one local zone to one provider account. Carries the provider's id for that zone (provider_remote_id) plus any free-form metadata the plugin chose to round-trip. |
A zone is bound to at most one provider account at a time; multi-provider mirroring isn't a goal of this version.
Add a provider account¶
- Go to Configuration → Services → DNS provider configurations
(
/admin/config/services/dns_external/providers). - Click Add provider configuration, pick the provider plugin (e.g. ClouDNS), then Continue.
- Fill in the plugin's settings form. Plain identifier fields (account id, username, endpoint URL) accept text directly; secret fields point at Key entities — create the Key first (Configuration → System → Keys) if you haven't already. The label is admin-facing only; pick something that distinguishes the account if you run more than one (e.g. ClouDNS — production, ClouDNS — staging).
- Save. The configuration appears on the collection page.
Import zones from a provider¶
- From the provider configuration collection, click Import zones.
- Pick the provider account whose zones you want to discover.
- The next page lists every zone the provider account exposes. Tick the ones you want to bring into Drupal and click Import selected.
What happens per zone:
- A local
dns_zoneis created (Punycode-canonicalized). - All records the provider returns are materialized as
dns_recordentities. Each carries the provider's id for that record (provider_remote_id) so the pusher can later update them in place rather than re-creating duplicates. - A binding entity is created tying the zone to the provider account.
What import refuses¶
The importer refuses to import into an existing local zone — if a
dns_zone with the same name already exists in Drupal, the row in the
discovery list is disabled with a "delete first to re-import" hint.
Re-import / merge semantics ship with bidirectional sync; until then,
delete the local zone first if you want to bring in the provider's
copy fresh.
What import skips¶
Per record, the importer skips and logs rather than aborting the zone:
- Unsupported record types: anything outside the eleven core
types plus the seven
dns_extrastypes (DNAME, SSHFP, TLSA, SMIMEA, OPENPGPKEY, DS, DNSKEY). Watch thedns_externallog channel; the count appears in the on-screen summary. - Records that fail validation: malformed targets, out-of-range TTLs, IP addresses in the wrong family, etc. The same log channel carries the per-record reason.
Mass-import success is reported with a count; partial success (records skipped) renders as a warning so you know to inspect the log.
Push a zone to its provider¶
The push button lives on each zone's binding page:
/dns/{zone}/external → Push to provider.
A confirmation page summarizes the scope (zone name, provider account) before submission, since the operation writes to a remote account that may serve more than one zone.
What push does, per record:
| Local state | Action |
|---|---|
Record has no provider_remote_id |
Calls the plugin's pushRecord. Stamps the returned id back on the local record. |
Record has a provider_remote_id |
Calls pushRecordUpdate. The remote id is preserved. |
If the binding has no provider_remote_id yet (you're pushing a
locally-created zone for the first time), push also calls pushZone
once and stamps the returned id on the binding.
What push does NOT do¶
- It doesn't sync deletes. A record you delete locally is not removed from the remote — until bidirectional sync ships, you have to delete those by hand on the provider side. The reason is scope: a sync that touches deletes needs a diff against the remote, which is a different operation than the strict local→remote write this push performs.
- It doesn't update the zone metadata after first push. The
one-time
pushZonecall sets things like the zone type (master/slave/geofor ClouDNS); changes to those settings via the binding edit form aren't synced. If you need to change zone-level metadata on the remote, do it in the provider's own console for now.
Failure modes¶
- Zone-level failure (
pushZoneitself fails): nothing is written remotely or locally. Status is reported as failed; check the log for the API response. - Per-record failure: the loop continues. Records that succeeded
keep their stamped
provider_remote_id; the failed ones don't, so a re-push tries them again as creates. The result message shows a N created, M updated, K failed summary.
A re-run of push is the standard recovery for transient API issues.
Permissions¶
| Permission | What it grants |
|---|---|
administer dns providers |
Add / edit / delete provider configurations and bindings; run import; run push. Restricted access. |
view records on a zone (per-zone) |
View the binding row on /dns/{zone}/external so zone owners and granted collaborators can see whether their zone is bound and to which provider account. |
Mutating provider configurations and bindings stays admin-only in this version because credentials and remote-API responsibility are admin concerns. Zone owners and granted collaborators can see that their zone is bound, but not change the binding.