Self-hosted service
PowerDNS-Admin/PowerDNS-Admin avatar
PowerDNS-Admin/PowerDNS-Admin

PowerDNS-Admin: the current image is named pda-legacy, and PowerDNS below 5.0 was dropped anyway

A PowerDNS web interface with advanced features

2,823 stars687 forksPythonMIT

At a glance

What is it?
A Flask web interface for the PowerDNS authoritative server, with zone templating, role and zone level access control, four authentication backends and an API. Its documentation has to explain that its own Docker image is called legacy, it drops support for old PowerDNS releases that upstream still patches for security, and it selects no database for you.
Who is it for?
This is a reasonable choice if you want a web interface with zone templating and real access control in front of PowerDNS, and the Docker path gets you running in one command. Two things to settle before you deploy it.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 7 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 4, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The current image is named pda-legacy and the README explains why

The one-command path runs an image whose name says legacy:

code
$ docker run -d \
    -e SECRET_KEY='a-very-secret-key' \
    -e SQLALCHEMY_DATABASE_URI='sqlite:////data/powerdns-admin.db' \
    -v pda-data:/data \
    -p 9191:80 \
    powerdnsadmin/pda-legacy:latest

The README then adds a note about the image name, saying that while the image is called pda-legacy it is the current and actively maintained version, and that the name is a historical artifact. So the project has kept an identifier that now describes the opposite of what it means, and the documentation has to spend a paragraph correcting it. That matters practically, because a name containing the word legacy is exactly what an operator filters for when deciding what to run in production, and a stale tag on a current build is worse than a confusing one.

No database is chosen for you and the compose file ships example passwords

The run command has to pass a database URI explicitly, and the README states plainly that PowerDNS-Admin does not select a database by default. The compose path is different: the included configuration starts MySQL and connects the application to it automatically. That convenience comes with a warning attached, because the file contains example database passwords that the README says must be replaced before deploying. Both routes are documented, so the failure mode is a deployment that starts successfully and is reachable on a local port with credentials that were published in a repository. The application itself then listens on port 9191 on the host, mapped to port 80 in the container.

Database credentials can arrive split, encoded, or from a secrets file

The configuration surface for the database is wider than the single URI the first example uses. Database settings can be passed either as one connection URI or as separate variables for driver, user, password, host, port, name and extra parameters. The README explains that the split form is percent-encoded automatically, so a password containing an at sign or a hash does not have to be encoded a second time by the operator. There is a separate extra-parameters variable for driver specific URI flags, with encrypted connections given as the example. And the Docker secrets convention is supported: appending a file suffix to an environment variable name makes the application read that value from a file instead, with a database password file under the run secrets directory given as the example. So the same setting has four input paths and the choice is a deployment concern, not a code one.

Support for PowerDNS below 5.0 was dropped while upstream still patches it

The compatibility section is the most consequential paragraph in the file. It says the project is built and tested against the current stable release of the authoritative server plus recent prior minor releases, and that support for versions older than 5.0 has been dropped entirely. Then it adds the clause that makes the decision arguable: even where PowerDNS itself continues to backport critical and security fixes to those older versions. So this project has decided that its own support window is shorter than the upstream server's security window, and it says so in those words. The exact supported versions live in a JSON support file rather than in the prose, alongside a second file for browser versions, so the matrix is machine readable but has to be fetched separately to answer the question.

The release list mixes a calendar version with two 0.6 releases

Three releases are listed and they do not share a version scheme. The newest is numbered with a year, a month and a patch, published 2026-08-30. The two before it are numbered zero point six, published 2026-08-05 and 2026-08-07. So the project changed from a semantic version line to a calendar version line within the space of a few weeks, and the release list now contains both. Any automation that compares these tags as semantic versions will read the calendar version as lower than the 0.6 releases, because a leading two is less than a leading zero in string ordering. That is the sort of thing that breaks a deployment pipeline silently, and the repository does not document the switch or the rule for which scheme new work continues under.

Every Python dependency is pinned exactly and four entries are commented out

The requirements file pins every entry with an exact equality, with no version ranges anywhere, which for a Flask application of this size is an unusual amount of control. Four lines are commented out rather than deleted, and one of them carries a reason: a version range for a JSON schema library is disabled with a note that it stays disabled until an upstream pull request in the Swagger client library lands, and the library itself is pinned to a fixed version instead. A configuration library, a CSS minifier and a small compatibility shim are also commented out with no explanation. The set of authentication libraries is what the feature list implies: a SAML toolkit, an OAuth library, an LDAP binding, a one time password library, a QR code generator, and a captcha module, plus bcrypt for hashing and a password strength estimator.

An HTTPS enforcement extension is pinned alongside Flask 3.1.3

One entry in the requirements file is a Flask extension whose entire job is to redirect requests to HTTPS, pinned to version zero point one point five, in the same list as Flask itself at three point one point three and Flask-SQLAlchemy at three point one point one. That pairing is worth a second look for anyone deploying this, because the extension sits at a much earlier version number than everything around it and is several major Flask generations behind the framework it plugs into. Whether it still works is not something the repository states. What the repository does state is the alternative route: the Docker and compose examples use plain HTTP, the application is reached at a local HTTP address, and the README's guidance on the secret key points at Flask's own configuration documentation rather than at any transport setting.

The frontend manifest pins build tooling exactly and declares no scripts

The asset build is a Yarn 4 project with a lock file and a configuration file at the root, and its manifest is unusually short: a package manager declaration and a dependencies block, with no name, no version and no scripts section at all. So whatever assembles the stylesheets and scripts is not declared in this file. The dependency list itself mixes two philosophies. The build tooling is pinned to exact versions, including an admin template, a CSS framework, a font icon set, a popper library and two datatables packages at an identical fixed version. The libraries use caret ranges instead, among them jQuery, a validation plugin, a timer helper and a client side reactive binding library. Two datatables packages sit at one fixed version while their plugins package floats on a caret range of the same major.

Editorial conclusion

This is a reasonable choice if you want a web interface with zone templating and real access control in front of PowerDNS, and the Docker path gets you running in one command. Two things to settle before you deploy it. Decide where the database configuration comes from, because the application picks none and the shipped compose file carries example passwords that must be replaced before it goes anywhere real. And decide whether the PowerDNS versions you run are still on the supported list, because this project has deliberately dropped everything below 5.0 while stating that upstream keeps backporting security fixes to those older releases.

Frequently asked questions

How do I install PowerDNS-Admin?

The quickest route is Docker. The README gives a docker run command with a secret key, an explicit SQLite URI, a named volume and port 9191 mapped to 80, and a second route using the included compose file, which starts MySQL. Installing directly on a system is documented separately under the project's own wiki rather than in the README.

Which PowerDNS versions does PowerDNS-Admin support?

It is built and tested against the current stable release of the authoritative server plus recent prior minor releases, and support for versions older than 5.0 has been dropped entirely. The exact PowerDNS, Python and browser versions are listed in the app-support.json file.

How does PowerDNS-Admin differ from Poweradmin?

The repository makes no comparison to Poweradmin anywhere. Its own feature list covers forward and reverse zone management, zone templating, role and zone level access control, activity logging, four authentication backends, TOTP two factor authentication, DynDNS 2 support and an API for zone and record management.

What authentication methods does PowerDNS-Admin support?

Local users, SAML, LDAP against OpenLDAP or Active Directory, and OAuth against Google, GitHub, Microsoft Entra ID or OpenID. Two factor authentication is supported with TOTP, and the requirements list includes a one time password library and a QR code generator.

Does PowerDNS-Admin have a default database?

No. The README states that PowerDNS-Admin does not select a database by default, which is why the Docker example passes an explicit connection URI. The compose configuration starts MySQL instead, and its example database passwords are to be replaced before deploying.

Official sources

  1. Issues
  2. License: MIT
  3. PowerDNS-Admin/PowerDNS-Admin on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/powerdns-admin-powerdns-admin.svg)](https://hysenlabs.com/projects/powerdns-admin-powerdns-admin)