Basic Configuration¶
Poweradmin v4.x uses an array-based configuration format in config/settings.php.
Note: Upgrading from v3.x? The old flat $variable format was removed in 4.1.0. See Legacy Configuration to map the old names onto the keys below.
Configuration File¶
Create config/settings.php with your custom settings. The file config/settings.defaults.php contains all defaults - do not edit it directly as changes will be overwritten during upgrades.
<?php
return [
'database' => [
'host' => 'localhost',
'name' => 'powerdns-db',
'user' => 'poweradmin-db-user',
'password' => 'poweradmin-db-user-password',
'type' => 'mysql',
],
'security' => [
'session_key' => 'change_this_key',
],
'dns' => [
'hostmaster' => 'hostmaster.example.com',
'ns1' => 'ns1.example.com',
'ns2' => 'ns2.example.com',
],
];
Configuration Precedence¶
Poweradmin always layers config/settings.php (or the file named by PA_CONFIG_PATH) over config/settings.defaults.php.
In Docker, PA_* variables do not override a settings file. If config/settings.php (or the PA_CONFIG_PATH file) exists and is not empty, the container uses it as is and ignores every PA_* variable except PA_CONFIG_PATH. Only when that file is missing or empty does the entrypoint generate it from the PA_* variables, after resolving PA_*__FILE secrets.
Note: A secret and its plain environment variable are mutually exclusive, not layered. If both
PA_FOOandPA_FOO__FILEare set, the container logs an error and exits rather than preferring one over the other.
Protecting Credentials Outside Docker¶
config/settings.php holds the database password and the session key in plain text, so on a
non-container install the file permissions are the protection.
- Make the file readable by the web server user and nobody else. With Apache or php-fpm running as
www-data, that ischown root:www-data config/settings.phpandchmod 640 config/settings.php. - Keep it out of version control and out of any backup that is world-readable.
- Rotate
security.session_keyif the file is ever exposed; it signs session data.
Two things that work in Docker do not apply here:
- The
__FILEsecrets convention is a container feature. It is implemented indocker-entrypoint.sh, which translatesPA_FOO__FILEintoPA_FOObefore PHP starts. Nothing in the application reads it, soPA_DB_PASS__FILEhas no effect on a bare-metal install. See Docker Secrets for what it does cover. PA_*environment variables are also entrypoint-driven. They are turned into settings while the container starts, not read at runtime.
The one environment variable the application itself reads is PA_CONFIG_PATH, which points at an
alternative settings file:
That lets you keep configuration outside the document root - on a read-only deployment, or where
the application directory is replaced wholesale on upgrade. When it is unset, Poweradmin falls back
to config/settings.php.
Configuration Sections¶
The configuration is organized into logical sections:
| Section | Description |
|---|---|
database |
Database connection settings |
security |
Password policies, session management, MFA |
dns |
Nameserver details, SOA defaults, TLD checks |
interface |
UI preferences, themes, display options |
logging |
Logging configuration (file, syslog, database) |
pdns_api |
PowerDNS API integration |
mail |
Email configuration for notifications |
dnssec |
DNSSEC functionality |
ldap |
LDAP/Active Directory authentication |
oidc |
OpenID Connect authentication |
saml |
SAML authentication |
modules |
Optional modules: CSV export (modules.csv_export), zone import/export (modules.zone_import_export), secondary zone import over AXFR (modules.secondary_zone_import), WHOIS (modules.whois), RDAP (modules.rdap), DNS wizards (modules.dns_wizards), mail template previews (modules.email_previews) |
notifications |
Notification toggles: notifications.zone_access_enabled (default false) for zone access change emails, notifications.change_request_enabled (default false, v4.6.0+) for change request emails, notifications.change_request_soa_contact (default false, v4.6.0+) to include the zone's SOA contact |
approval |
Change approval workflow: approval.enabled, approval.require_review_for_all and approval.allow_self_approval (v4.6.0+) - see Change Requests |
api |
REST API configuration |
user_agreement |
User agreement system |
misc |
Timezone, conflict handling, etc. |
Database Settings¶
| Setting | Default | Description |
|---|---|---|
database.host |
- | Database server hostname |
database.port |
- | Database port (optional) |
database.user |
- | Database username |
database.password |
- | Database password |
database.name |
- | Database name |
database.type |
- | Database type: mysql, mysqli, pgsql, sqlite |
database.charset |
- | Connection charset (e.g., utf8) |
database.file |
- | SQLite database file path |
database.debug |
false | Log SQL queries |
database.pdns_db_name |
(empty) | Separate PowerDNS database, MySQL/MariaDB only (v3.8.0+) |
database.sqlite_wal |
true | SQLite only: switch the file to WAL journal mode on connect; set false on NFS (v4.6.0+) |
Security Settings¶
| Setting | Default | Description |
|---|---|---|
security.session_key |
change_this_key | Session encryption key (change this!) |
security.password_encryption |
bcrypt | Hash algorithm: bcrypt, argon2i, argon2id |
security.password_cost |
12 | Bcrypt cost parameter |
security.login_token_validation |
true | CSRF protection for login |
security.global_token_validation |
true | CSRF protection globally |
For password policies and MFA settings, see Security Policies.
Interface Settings¶
| Setting | Default | Description |
|---|---|---|
interface.language |
en_EN | Default language |
interface.enabled_languages |
multiple* | Available languages |
interface.theme |
default | Theme name (default, modern, or your own directory under theme_base_path) |
interface.style |
light | UI style: light or dark |
interface.rows_per_page |
10 | Rows per page in lists |
interface.session_timeout |
1800 | Session timeout in seconds. Must be a positive integer; from 4.5.0 a value of 0 is rejected with a configuration error instead of logging users out on their next request. The timeout cannot be disabled - use a large value |
interface.session_max_lifetime |
0 | End a session this many seconds after sign-in, however active it stays; 0 turns it off and leaves only session_timeout. For example 43200 signs users out after 12 hours (v4.6.0+) |
interface.title |
Poweradmin | Application title |
interface.application_url |
(empty) | Public base URL of the install. Required for OIDC, SAML, password reset and emailed links |
interface.web_enabled |
true | Serve the web interface; false runs API-only - see the Headless Quickstart |
interface.display_serial_in_zone_list |
false | Show serial in zone list |
interface.display_template_in_zone_list |
false | Show template in zone list |
interface.show_zone_comments |
true | Enable zone comments |
interface.show_record_comments |
false | Enable record comments |
interface.show_zone_limit_column |
false | Show owned zones and the zone limit in the users and groups lists (4.6.0) |
interface.add_reverse_record |
true | Show PTR record checkbox |
interface.add_domain_record |
true | Show A/AAAA checkbox in reverse view |
interface.show_record_id |
false | Show record ID in edit form |
interface.position_record_form_top |
true | Add record form at top |
interface.position_save_button_top |
false | Save button at top |
interface.show_forward_zone_associations |
true | Show associated forward zones in reverse zone list (v4.0.5+) |
interface.display_hostname_only |
false | Show only hostname part in zone edit form (strips zone suffix). Site-wide default; from v4.4.0 each user can override this in their account preferences. |
interface.wide_layout |
false | Use the full browser width instead of a fixed-width page. Site-wide default; from v4.5.0 each user can override this in their account preferences. |
* Default languages: ar_SA, bg_BG, bs_BA, cs_CZ, da_DK, de_DE, el_GR, en_EN, es_ES, et_EE, fa_IR, fi_FI, fr_FR, ga_IE, he_IL, hi_IN, hr_HR, hu_HU, id_ID, it_IT, ja_JP, ko_KR, lt_LT, lv_LV, ms_MY, nb_NO, nl_NL, pl_PL, pt_BR, pt_PT, ro_RO, ru_RU, sk_SK, sl_SI, sq_AL, sr_RS, sv_SE, th_TH, tr_TR, uk_UA, vi_VN, zh_CN, zh_TW (et_EE, fi_FI, hr_HR, hu_HU, lv_LV, ro_RO, sk_SK, sr_RS added in v4.4.0)
Tip: If you experience slow loading or timeout errors on the reverse zones page, set
show_forward_zone_associationstofalse. This disables the lookup of associated forward zones which can be slow with many PTR records.
For UI customization, see UI Customization.
DNS Settings¶
| Setting | Default | Description |
|---|---|---|
dns.hostmaster |
- | Default hostmaster (e.g., hostmaster.example.net) |
dns.ns1 |
- | Primary nameserver |
dns.ns2 |
- | Secondary nameserver |
dns.ns3 |
- | Third nameserver (optional) |
dns.ns4 |
- | Fourth nameserver (optional) |
dns.ttl |
86400 | Default TTL (seconds) |
dns.soa_refresh |
28800 | SOA refresh (seconds) |
dns.soa_retry |
7200 | SOA retry (seconds) |
dns.soa_expire |
604800 | SOA expire (seconds) |
dns.soa_minimum |
86400 | SOA minimum (seconds) |
dns.zone_type_default |
MASTER | Default zone type: MASTER or NATIVE |
dns.strict_tld_check |
false | Allow only official TLDs |
dns.top_level_tld_check |
false | Prevent top-level TLD creation |
dns.third_level_check |
false | Prevent third-level domain creation |
dns.txt_auto_quote |
false | Auto-quote TXT records |
For more DNS options, see DNS Settings.
Change Approval Settings¶
| Setting | Default | Description |
|---|---|---|
approval.enabled |
false | Route the zone changes of request-only users through review (v4.6.0+) |
approval.require_review_for_all |
false | Every zone change becomes a change request, even for editors and administrators (v4.6.0+) |
approval.allow_self_approval |
true | Whether a requester may approve their own change request (v4.6.0+) |
Email for filed and decided requests is a separate switch, notifications.change_request_enabled, and needs mail.enabled. See Change Requests.
Miscellaneous Settings¶
| Setting | Default | Description |
|---|---|---|
misc.timezone |
UTC | Application timezone, used for SOA serial generation (e.g. Europe/Berlin, Asia/Shanghai) |
misc.display_stats |
false | Show memory/execution stats |
misc.display_errors |
false | Show PHP errors (disable in production) |
misc.show_generated_passwords |
true | Display generated passwords |
misc.edit_conflict_resolution |
last_writer_wins | Conflict strategy* |
misc.record_comments_sync |
false | Sync A/PTR record comments |
misc.template_cache |
false | Cache compiled Twig templates on disk for faster rendering (v4.5.0+) |
misc.template_cache_path |
(empty) | Directory for compiled templates; empty uses var/cache/twig (v4.5.0+) |
* Conflict resolution strategies:
last_writer_wins- The save goes through; rows you edited replace what the zone holds for them now, even if someone else changed them after the form was openedonly_latest_version- The save is refused when the zone's SOA serial changed since the form was opened
The check applies to direct saves of the record table on the zone edit page. It compares the SOA serial, so anything that moves the serial (a record write, the zone comment, signing) refuses the whole form, and a change that does not move the serial is not detected. A save that files a change request is not refused; the review page notes when the serial moved since it was filed. The inline add form, adding, editing or deleting a single record, and API v2 writes are not checked themselves, but they move the serial, so a zone edit form opened before them is refused.
From 4.6.0 a rejected save keeps the submitted records and comment on the page (when the browser sent only the edited rows, which it does with JavaScript on), marks the rows that differ from what the zone holds, and lets you resubmit instead of retyping.

Template caching¶
Enabling misc.template_cache compiles Twig templates to PHP once and reuses them, which takes the
compile step out of every request. The cache directory must be writable by the web server user. If
it cannot be created or written, Poweradmin logs a warning and falls back to uncached rendering
rather than failing the request.
Compiled templates are revalidated against their source files, so an upgrade that ships new templates takes effect without clearing the cache by hand.