This guide takes you from a downloaded zip to a working, selling DNS module — step by step. New to the concepts? Skim How It Works first (5 minutes); it makes every step below obvious.
At a glance: upload → enter license → make storage/ writable → activate → schedule cron → add a server → create a package → assign it to a product. Done.
| WHMCS | 8.x – 9.x |
| PHP | 7.4 – 8.3, with curl and json |
| Recommended PHP ext | sodium (credential encryption), simplexml (Route 53 / XML backends), openssl (Google Cloud DNS) |
| ionCube Loader | Already present on every WHMCS host (the build is ionCube-safe) |
| Access | Full Administrator in WHMCS; ability to add a cron job |
- Download and unzip the package. Inside you'll find:
DNS-Manager-vX.Y.Z/ ├── INSTALL.txt ├── HOW-IT-WORKS.txt ├── CHANGELOG.txt ├── LICENSE.txt └── modules/addons/dnsmanager/ ← this is what you upload - Upload the
modules/addons/dnsmanager/folder into your WHMCS root, so it ends up at:(Merge with the existing/your-whmcs/modules/addons/dnsmanager/modules/addons/directory — don't replace it.)
The package ships a license.php (or license_RENAME.php) placeholder. If a RENAME file is present, rename it to license.php. You'll also enter the key in the WHMCS UI during activation (Step 4) — either is fine; the UI key is what the module uses.
The module keeps a private, web-blocked cache in storage/. Make it writable by the web server:
chmod -R 0755 /your-whmcs/modules/addons/dnsmanager/storage
- In WHMCS: Configuration → System Settings → Addon Modules (older WHMCS: Setup → Addon Modules).
- Find DNS Manager and click Activate.
- Click Configure, then:
- Paste your License Key.
- Under Access Control, tick Full Administrator (and any other admin roles that should manage DNS).
- Review the options (you can change them anytime — see Configuration reference below). Sensible defaults are pre-set.
- Save Changes.
On activation the module creates its database tables and seeds a ready-to-use "Built-in DNS" server so you can try things immediately.
DNS Manager runs background jobs (provisioning retries, backups, drift checks, sync) on a small cron script. Add this to your server's crontab to run every 5 minutes:
*/5 * * * * php -q /your-whmcs/modules/addons/dnsmanager/cron/cron.php >/dev/null 2>&1
The module still works for live actions without this, but scheduled automation (auto-backups, drift detection, secondary sync, queued imports/migrations) needs it.
Go to Addons → DNS Manager → Servers → Add a server. Pick the Type for your backend and fill in its connection details, then click Save and Test.
Common backends (you only need the ones you'll use):
| Backend | What to enter |
|---|---|
| Built-in | Nothing — already added; great for free/self-service zones and testing. |
| PowerDNS V4 | Hostname, Port (default 8081), API token (in API token). Optional server_id in Backend options (default localhost). |
| Cloudflare | API token (scoped DNS-edit) in API token; optionally an account_id in Backend options. |
| cPanel / WHM | Hostname, Port 2087, Username (root/reseller) + a WHM API token in API token. |
| BIND 9 | Backend options JSON: {"zone_dir":"/var/named","conf_path":"/etc/named.conf","reload_cmd":"rndc reload"} — the paths must be writable by the web user. |
| AWS Route 53 | API key = Access Key ID, API secret = Secret Key; optional region in options. |
| DirectAdmin | Hostname, Port 2222, Username + Password (or login key). |
| Nameservers | For any backend, list the NS records new zones should advertise. |
Then:
- Click Test — confirms the credentials connect.
- Click Run conformance — proves the backend correctly creates a zone, adds records of every type, reads them back exactly, updates, deletes, and tears down. A green result means you can rely on it. (Backends are also pre-graded Verified / Beta / Experimental.)
A package is the ruleset that turns a product into DNS. Go to Packages → Add a package:
- Name — e.g. "Hosting DNS".
- Server — the backend zones will be created on.
- Zone limit / Record limit —
0means unlimited. - Allowed record types — leave all ticked, or restrict (e.g. no NS).
- Default TTL — e.g. 3600.
- Provisioned record set — the template applied when a zone is created (create one under Record sets first if you want auto-seeded records).
- Assign to — choose Product, Product addon, or Domain TLD, and list the IDs/TLDs (e.g. product IDs
10, 11, or TLDscom net). - Tick Active.
Want free, self-service DNS (no purchase)? Tick Free / self-service package on a package pointed at the Built-in server.
In the module configuration (Configure), ensure Auto-provision zones is on. Now, whenever a customer's product (matched by your package) activates — or a domain on a matched TLD is registered — DNS Manager creates the zone and seeds it from the record set. No further action needed.
Still in Configure, switch on exactly what you want clients to do:
Client area— show the DNS area and nav link.Clients may create zones,… add slave zones,… manage rDNS,… use record sets,… use bulk actions,… manage backups,… import/export (BIND).DNS health checks,Propagation checker— the helpful read-only tools.Clients may toggle DNSSEC— where the backend supports it.
- AI assistant — set
AI DNS assistanton, pick an AI provider (Anthropic, OpenAI, DeepSeek, Gemini, Azure, or OpenAI-compatible), paste the AI API key, set the AI model (e.g.claude-sonnet-4-6,gpt-4o-mini,deepseek-chat), and for Azure/compatible set the AI base URL. - Webhooks — set
Outbound webhookson, then add endpoints (they receive HMAC-signed events). - REST API — issue scoped tokens with the CLI:
php modules/addons/dnsmanager/cli.php token <clientId> records:write— the API lives at/modules/addons/dnsmanager/api.php(OpenAPI spec indocs/). - Secondary / failover DNS — add a second server and pair it to a zone for redundancy.
- Resilience — leave on; tune
requests/min per serverand the breaker threshold if a provider is rate-limited.
- Place a test order for a product your package covers (or register a covered TLD).
- In Addons → DNS Manager → Zones, confirm the zone was created on the right server.
- Open the zone → check the seeded records and the Health score.
- As the client, open DNS Management, add a record, and Check propagation.
If the zone appears and records round-trip, you're live.
Upload the new modules/addons/dnsmanager/ over the existing files (overwrite). WHMCS detects the new version and runs the upgrade routine automatically; your servers, packages, zones and settings are preserved. No reconfiguration needed.
"Cannot declare class Arahoster\Licensing\License…" on activation. You're running another arahoster product (e.g. eKYC Guard) that shares the same license client. Update both modules to their latest version (which guards against this) and re-upload. Fixed in DNS Manager 1.2.3+.
License shows inactive / red banner. Check the key in Configure, ensure the server can reach the internet, and that storage/ is writable (the license cache lives there). The module fails open, so core DNS keeps working from cache.
Scheduled jobs aren't running (no auto-backups / drift). Confirm the cron from Step 5 is installed and runs php …/cron/cron.php. Check Tasks for queued/failed jobs and Logs for errors.
A backend "Test" fails. Re-check the hostname/port/credentials. For API backends, confirm the token's scopes (Cloudflare: DNS edit; cPanel: WHM API token). For BIND 9, confirm the zone_dir/conf_path are writable by the web user. Run Run conformance for a detailed per-operation report.
Records don't appear for a zone. The records live on the backend — open the zone to load them live. If the backend recently changed outside the module, the drift task will flag it.
A zone wasn't auto-created on order. Confirm a package is assigned to that product/TLD, the package is Active, and Auto-provision is on. Check Logs for a provision entry.
Deactivating the addon keeps your data (zones, records metadata, settings). To remove everything, deactivate and then drop the mod_dnsmanager_* tables manually.
Open a support ticket in the client area at https://me.arahoster.com (Submit Ticket → https://me.arahoster.com/submitticket.php).
A plain-English guide to what DNS Manager is, the ideas it's built on, and how everything fits together.
DNS Manager turns DNS into something you can sell, automate and delegate inside WHMCS. It gives your clients a clean area to manage their own DNS zones and records, gives you full control over what they can do, and connects to 31 different DNS platforms (PowerDNS, Cloudflare, cPanel/WHM, BIND 9, AWS Route 53, Google Cloud DNS, DirectAdmin, Plesk and more) through one consistent interface. Zones are created automatically when a customer orders, and a layer of intelligence — DNS health scoring, propagation checks, and an AI assistant — helps everyone avoid the mistakes that usually become support tickets.
Everything in DNS Manager is built from five simple concepts. Once these click, the whole module makes sense.
SERVER PACKAGE ZONE RECORD
(where DNS lives) (rules & limits) (a domain's DNS) (one DNS entry)
─────────────── ─────────────── ────────────── ─────────────
PowerDNS, cPanel, "VPS DNS": max 5 example.com www A 1.2.3.4
Cloudflare, BIND, zones, 50 records, on a Server, @ MX 10 mail…
Route 53, … allowed types … owned by a client _dmarc TXT …
RECORD SET
(a reusable template of records, e.g. "Google Workspace")
- Server — where DNS is actually hosted. A server is one backend (e.g. a PowerDNS box, a Cloudflare account, a cPanel/WHM server). You add as many as you like and DNS Manager talks to each through a driver.
- Package — the rules. A package maps your WHMCS products/addons or domain TLDs to a server, and sets limits: how many zones, how many records per zone, which record types are allowed, the default TTL, and which record set to apply when a zone is created.
- Zone — a domain's DNS (e.g.
example.com). A zone belongs to a client and lives on a server. DNS Manager tracks who owns it; the records themselves live on the backend. - Record — a single DNS entry (A, AAAA, CNAME, MX, TXT, SRV, CAA, NS, PTR…).
- Record Set — a reusable template of records with merge fields like
{$domain}and{$ip}, so "set up email" or "point this domain at my server" becomes one click.
Key idea: the
zonestable is the system of record for who owns what. The records themselves are read from and written to the backend (Cloudflare, cPanel, etc.). The built-in backend is the exception — it stores records in the module's own database, so it works with zero configuration.
DNS platforms all speak different languages — Cloudflare has a JSON API, PowerDNS uses rrsets, cPanel uses WHM API, BIND uses zone files, Route 53 uses signed XML. DNS Manager hides all of that behind a single driver interface. Every backend is a "driver" that implements the same operations (create zone, add record, list records, delete, DNSSEC, reverse DNS). The rest of the module never cares which backend a zone is on.
This means:
- You can run different backends side by side — some zones on PowerDNS, some on Cloudflare, some on a customer's cPanel — all managed from one place.
- Adding a backend in future is a single driver class; nothing else changes.
Each backend is graded so you always know what you're switching on:
| Tier | Meaning |
|---|---|
| ???? Verified | Passes the built-in conformance suite end-to-end. |
| ???? Beta | Implemented to the documented API; verify on your own server. |
| ???? Experimental | API is under-documented; test carefully before production. |
You can prove any backend on your own server with the conformance suite (Admin → Servers → Run conformance, or cli.php conformance <id>). It creates a throwaway test zone, runs every operation, checks the round-trips, and cleans up — turning "I hope this works" into "I tested it."
This is the heart of selling DNS. When a customer's order activates, DNS Manager creates their zone for them — no admin action required.
Customer orders a product
│
▼
WHMCS activates the service ──(AfterModuleCreate hook)──► DNS Manager
│
▼
Is a PACKAGE assigned to this product? ──no──► nothing happens
│ yes
▼
Create a ZONE for the service's domain on the package's SERVER
│
▼
Seed it from the package's RECORD SET (with {$domain}/{$ip} filled in)
│
▼
Zone is live. The customer can now manage it in their client area.
The same happens for domain registrations/transfers (matched by TLD), and zone status follows the service: suspend a service and its zones are flagged; terminate it and (if you enable it) the zones are removed.
You stay in control: provisioning only happens where you've assigned a package, so free trials or products that shouldn't get DNS simply don't.
In the WHMCS client area (under DNS Management), clients can — within the limits you set and only for the features you switch on:
- Create and manage zones (master, and optionally slave zones).
- Edit records with validation (a bad IP or a CNAME-at-apex is rejected with a clear message, not silently broken).
- Bulk actions across many zones at once.
- Apply record sets and build their own.
- Reverse DNS (PTR) management where the backend supports it.
- Backups & restore, and BIND import/export.
- See a DNS Health score for each zone and check propagation.
- Ask the AI assistant to propose changes (which they then confirm).
Every one of these is gated by a setting, so you decide exactly how much self-service to offer.
Under Addons → DNS Manager:
- Dashboard — zone/server/package counts and recent activity.
- Zones — every client's zones; open one to edit records, lock it, migrate it to another server, toggle DNSSEC, import/export BIND, and see its health, drift and audit history.
- Servers — add/edit backends, test connections, run conformance, see maturity badges.
- Packages — the rules that drive provisioning and limits.
- Record sets — global templates you offer to everyone.
- Tasks — the background job queue and its status.
- Audit — every change with a diff and a one-click rollback.
- Deleted zones — restore a removed zone.
- Logs & Settings.
Heavy or repeated work runs in the background so a page load is never blocked. A small script (cron/cron.php) runs every ~5 minutes and processes queued tasks:
| Task | What it does |
|---|---|
migrate |
Move a zone (with records) to another server. |
import |
Pull existing zones in from a backend. |
sync |
Keep master/slave zones in step. |
clean |
Remove unused/idle zones per your rules. |
backup |
Scheduled zone backups (keeping the last N). |
drift |
Detect records changed directly on the backend. |
conformance |
Run the backend test suite and cache the result. |
secondary |
Sync zones that have a secondary/failover backend. |
WHMCS's own daily cron also prunes old logs and finished tasks.
- DNS Health score (A–F) — analyses a zone for the mistakes that break email and websites: CNAME at the apex, dangling/conflicting records, missing or duplicate SPF, missing DMARC, MX pointing at a CNAME, wildcards, dangerously low TTLs, and duplicates. Each finding comes with a recommendation.
- Propagation checker — asks public resolvers (Cloudflare, Google) and the zone's authoritative nameservers what they see, and reports propagated / partial / pending. This answers the #1 DNS question — "is it live yet?".
- Presets — one-click record sets for Google Workspace, Microsoft 365, generic mail, SPF-hardening, DMARC, CAA (Let's Encrypt) and GitHub Pages.
- AI assistant — describe a goal in plain language ("fix my email deliverability"). The assistant returns a proposed set of changes that is always validated and never applied automatically — a human reviews and confirms. You bring your own model: Anthropic, OpenAI, DeepSeek, Google Gemini, Azure OpenAI, or any OpenAI-compatible/local endpoint (OpenRouter, Groq, Ollama, …). The AI only suggests; DNS Manager's validation and your confirmation are the safety net.
DNS is critical infrastructure, so the module is built to fail safely:
- Per-backend resilience — a token-bucket rate limiter and a circuit breaker protect each backend. If a provider gets unhealthy, its breaker trips and operations fail gracefully with a clear message instead of hammering the API.
- Idempotent writes — adding a record that already exists is a no-op success, so a retried cron run or a double-click never creates duplicates.
- Change audit + one-click rollback — every change is recorded as a diff you can revert.
- Anomaly detection — suspicious changes (apex/NS/MX changes, bulk deletes) are flagged as a DNS-hijack early warning.
- Drift detection — catches records changed directly on the backend, outside the module.
- Safety rails — blocked content strings (plain or regex), IP allow/deny lists, per-package limits, and zone locking.
- RBAC — roles (owner/manager/editor/viewer) with step-up confirmation on destructive actions.
- REST API (
api.php) — scoped, owner-bound bearer tokens (zones:read/write,records:read/write,admin). An OpenAPI spec ships indocs/openapi.yaml. - Webhooks — HMAC-signed events (record added/updated/deleted, anomaly detected) to your endpoints.
- Prometheus metrics (
metrics.php) — zone/server/task/record counts and license state for monitoring. - CLI (
cli.php) — list zones/servers, run conformance/drift, issue API tokens, print a zone's health, run the queue.
- Zone identity, packages, servers, record sets, reverse DNS, backups, tasks, audit changes, API tokens and webhooks live in the module's own database tables (prefixed
mod_dnsmanager_). - Record contents live on the backend (Cloudflare, cPanel, …) — except the built-in backend, which stores them in the database.
- Server credentials are encrypted at rest (libsodium) — only decrypted when a connection is made.
- A private
storage/folder (blocked from the web) holds the signed license cache.
DNS Manager is licensed with a key you enter in the module configuration. The license is verified once and then cached, so day-to-day operation never waits on the network. If the licensing server is briefly unreachable, the module keeps working from cache (fail-open) rather than breaking your DNS. Premium features stay enabled while your license is valid.
- You add a PowerDNS server, click Test (✓), then Run conformance (✓ Verified).
- You create a package "Hosting DNS" → PowerDNS, 10 zones, 100 records, all types, default TTL 3600, record set "Standard web + mail", assigned to your Web Hosting product.
- A customer orders Web Hosting for
example.com. On activation, DNS Manager auto-creates theexample.comzone on PowerDNS and seeds it from the record set (A@→server IP,wwwCNAME, MX, SPF). - The customer opens DNS Management, sees a Health score of B with a tip to add DMARC, clicks the DMARC preset, and the score goes to A.
- They add an
Arecord forapp, then click Check propagation — Cloudflare and Google both already see it: propagated. - Later, someone edits the zone directly on the server. The nightly drift task flags it, and you reconcile from the Audit tab.
That's the whole module: servers hold DNS, packages set the rules, zones and records are provisioned and managed automatically, and a layer of health, propagation, AI and safety keeps it all correct.