Headless / API-First Quickstart¶
If you want to drive PowerDNS from scripts, CI, or your own tooling without clicking through a web UI, Poweradmin can run in an API-first mode. The web interface stays available for the few things that need it (creating the first admin user, issuing API keys), but day-to-day zone and record management can happen entirely over the REST API.
This page gets you from zero to a scripted record update in about five minutes.
What you get¶
- A REST API (
/api/v2) with predictable JSON responses - Per-user API keys that can be revoked or rotated
- Interactive OpenAPI/Swagger docs at
/api/docs - The same validation Poweradmin applies in the web UI (record types, hostnames, TTL bounds, SOA serial bumps)
1. Start Poweradmin with the API enabled¶
The Docker image is the fastest path. Set PA_API_ENABLED=true so the API is
exposed, and PA_API_DOCS_ENABLED=true so you can explore endpoints
interactively.
docker run -d --name poweradmin -p 8080:80 \
-e DB_TYPE=sqlite \
-e PA_CREATE_ADMIN=1 \
-e PA_API_ENABLED=true \
-e PA_API_DOCS_ENABLED=true \
-v poweradmin-db:/db \
poweradmin/poweradmin:latest
DB_TYPE is required and has no default, so the container will not start
without it. No admin account is seeded: PA_CREATE_ADMIN=1 creates one named
admin with a generated password, which you can read from the log:
Set PA_ADMIN_PASSWORD to choose it yourself. For a production setup, point at
MySQL or PostgreSQL with the DB_* variables described in
Docker Installation.
2. Create an API key¶
API keys are issued through the web interface. This is a one-time step; once the key exists, you can do everything else from scripts - including turning the interface off, see Turning the web interface off.
- Open http://localhost:8080 and log in.
- Go to Settings -> API Keys (
/settings/api-keys). - Click Add API Key, give it a name (e.g.
ci-deploy), and copy the key. The full key is only shown once.
Store it somewhere your scripts can read it:
3. Verify the key works¶
You should get back a JSON envelope with an empty data array (or your existing
zones if any).
4. Create a zone¶
curl -X POST \
-H "X-API-Key: $PA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "example.com",
"type": "MASTER"
}' \
"$PA_URL/api/v2/zones"
The response includes the zone id you will use for subsequent requests.
5. Add a record¶
ZONE_ID=1 # from the previous response
curl -X POST \
-H "X-API-Key: $PA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "www.example.com",
"type": "A",
"content": "192.0.2.10",
"ttl": 3600
}' \
"$PA_URL/api/v2/zones/$ZONE_ID/records"
Poweradmin validates the record, writes it to PowerDNS, and bumps the SOA serial so secondaries pick up the change.
6. Explore the rest interactively¶
With PA_API_DOCS_ENABLED=true the full OpenAPI explorer is available at:
You can paste your API key into the "Authorize" dialog and try every endpoint from the browser.
When to use this mode¶
This setup is a good fit when:
- You are scripting record updates from CI, Terraform, or config management
- You want PowerDNS managed by an infrastructure team but exposed to developers as an API
- You do not want end users in a web UI at all, but still need Poweradmin's validation and audit logging
- You are integrating with the terraform-provider-poweradmin or the external-dns-poweradmin-webhook
The web interface remains available for operators who prefer it. If you would rather it were not reachable at all, see Turning the web interface off below.
Turning the web interface off¶
Added in 4.5.0. Setting interface.web_enabled to false runs Poweradmin
API-only: the router registers just the API routes and everything else answers
a JSON 404.
With Docker, set PA_WEB_ENABLED=false instead and restart the container.
What stays reachable¶
| Path | Notes |
|---|---|
/api/v2/* |
The public API, subject to api.enabled |
/api/docs, /api/docs/json |
Subject to api.docs_enabled |
/api/health, /ping |
Subject to health.enabled / health.ping_enabled |
/api/v1/* |
Still answers 410 Gone, so retired clients get a clear error |
Everything else - the login page, OIDC and SAML callbacks, the settings area,
and the session-based /api/internal/* endpoints used by the interface's own
JavaScript - returns 404. Poweradmin also skips starting a session entirely in
this mode, since the API carries its identity on the API key.
Two paths are files rather than routes, so this setting does not affect them:
install/ (delete the directory after installing, as usual) and
dynamic_update.php.
Issue the API key first¶
API keys are created in the web interface, so this is a post-installation setting rather than an installation one. The order is:
- Install normally, with the interface enabled.
- Create your admin user and issue an API key at Settings -> API Keys.
- Set
web_enabledtofalseand restart.
Nothing is locked away: to rotate a key or change a setting the interface owns,
set web_enabled back to true, restart, do the work, and turn it off again.
What is not covered by the API yet¶
The REST API focuses on zones, records, users, groups, permission templates, and zone templates. A few operator workflows still live only in the web UI:
- Initial admin user creation (handled by the installer)
- API key issuance and rotation (Settings -> API Keys)
- Some global settings under Settings -> Configuration
If a missing endpoint blocks you, please open an issue on the GitHub repository.
Next steps¶
- API Configuration - full list of API settings, web server requirements, security recommendations
- PowerDNS API Configuration - connecting
Poweradmin to PowerDNS itself, including the API-only backend mode
(
dns.backend = api) added in 4.3.0 - Dynamic DNS with cURL - a separate, simpler endpoint for IP-update scripts