Poweradmin v4.4.3 Docker Compose 部署指南

Docker Compose 三服务栈部署 Poweradmin v4.4.3 + PowerDNS 4.9.18 gmysql + MariaDB 10.11 的完整实录:编排文件全文、部署与解析验证闭环、8 个真实排障坑速查。

PoweradminDNS服务器域名服务网络2026/10/26

Poweradmin v4.4.3 Docker Compose 部署指南

目标:在一台 Ubuntu 22.04 服务器上,用 Docker Compose 部署「Poweradmin v4.4.3 + PowerDNS Authoritative 4.9.18(gmysql 后端)+ MariaDB 10.11」三服务栈,跑通「服务启动 → 管理员登录 → 建 master zone → 记录增/删/改 → dig 验证解析生效」的完整闭环,并沉淀全程踩到的 8 个真实故障点。本文全部命令与回显已在 Docker Engine 29.9.2(Compose v5.6.1)环境实测通过。

一、环境信息

项目取值
操作系统Ubuntu 22.04(root 用户)
Docker Engine29.9.2
Docker Composev5.6.1
Poweradminv4.4.3(官方镜像 poweradmin/poweradmin:4.4.3,解压后 761MB)
PowerDNS Authoritative4.9.18(官方镜像 powerdns/pdns-auth-49:4.9.18,解压后 378MB)
数据库MariaDB 10.11(官方镜像 mariadb:10.11,解压后 459MB)
网络隔离自定义 bridge 网络,子网 10.89.60.0/24
端口规划Web 界面 8131(映射容器 80);DNS 服务 5311(映射容器 53,TCP+UDP)
示例账号管理员 admin / q1w2e3r4;数据库 root q1w2e3r4
部署形态三服务同一栈、同一网络:Poweradmin 经 SQL 直连模式读写 PowerDNS 的 gmysql 库

💡 技术拓展:本篇采用 Poweradmin 的 SQL 直连模式(dns.backend='sql')——Poweradmin 与 PowerDNS 共用同一个 MariaDB 库,Poweradmin 直接读写其中的 domains/records 表,DNSSEC rectify 场景下 Poweradmin 另行调用 PowerDNS 的 HTTP API(见 compose 中的 PA_PDNS_API_URL/PA_PDNS_API_KEY)。若采用 API 后端模式(dns.backend='api'),Poweradmin 不需要数据库权限,全部变更经 PowerDNS REST API 下发,两种模式的取舍见《Poweradmin v4.4.3 介绍与选型指南》 3.1 节。

1.1 版本依据

  • Poweradmin v4.4.3 是 GitHub Releases 页当前标记「Latest」的版本(4.4 LTS 维护线补丁,发布说明确认从 v4.4.2 原地替换无需数据库迁移);
  • PowerDNS 4.9.18 与 MariaDB 10.11 是 Poweradmin 官方 README「Tested on」矩阵中 4.4.x 线的实测组合;
  • 镜像标签约定:stable 当前指向 4.4.x 线,latest 指向 4.5.x,4.4 跟踪 4.4 线最新补丁,生产建议固定精确版本标签(本文用 4.4.3)。

二、编排文件

2.1 目录结构

/opt/poweradmin/
├── docker-compose.yml    # 三服务编排
└── pdns.conf             # PowerDNS Authoritative 配置(必须挂载覆盖镜像默认值,见 3.2)

2.2 docker-compose.yml 全文

name: poweradmin-4.4.3-stack

networks:
  pa-net:
    driver: bridge
    ipam:
      config:
        - subnet: 10.89.60.0/24

services:
  db:
    image: mariadb:10.11
    container_name: poweradmin-4.4.3-db
    hostname: db
    restart: unless-stopped
    environment:
      MARIADB_ROOT_PASSWORD: q1w2e3r4
      MARIADB_DATABASE: powerdns
      MARIADB_USER: poweradmin
      MARIADB_PASSWORD: q1w2e3r4
    volumes:
      - db-data:/var/lib/mysql
    networks: [pa-net]
    healthcheck:
      test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
      interval: 5s
      timeout: 5s
      retries: 20

  app:
    image: poweradmin/poweradmin:4.4.3
    container_name: poweradmin-4.4.3-app
    hostname: app
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
    ports:
      - "8131:80"
    environment:
      # 数据库连接(Poweradmin 自身表与 PowerDNS gmysql 表共用一个库)
      DB_TYPE: mysql
      DB_HOST: db
      DB_PORT: "3306"
      DB_USER: poweradmin
      DB_PASS: q1w2e3r4
      DB_NAME: powerdns
      PA_INIT_PDNS_SCHEMA: "true"
      # DNS 默认值(新建 zone 时自动带入 SOA 字段)
      DNS_NS1: ns1.example.com
      DNS_NS2: ns2.example.com
      DNS_HOSTMASTER: hostmaster.example.com
      # PowerDNS API 集成(SQL 后端模式下用于签名 zone rectify)
      PA_PDNS_API_URL: http://pdns:8081
      PA_PDNS_API_KEY: pa-pdns-api-key-4.4.3
      # Poweradmin REST API 与文档页
      PA_API_ENABLED: "true"
      PA_API_DOCS_ENABLED: "true"
      # 会话与其他
      PA_SESSION_KEY: pa-4.4.3-session-key-0123456789abcdefXYZ
      PA_TIMEZONE: Asia/Shanghai
      # 管理员账号(无 PA_CREATE_ADMIN 时镜像不建任何用户)
      PA_CREATE_ADMIN: "true"
      PA_ADMIN_USERNAME: admin
      PA_ADMIN_PASSWORD: q1w2e3r4
    networks: [pa-net]

  pdns:
    image: powerdns/pdns-auth-49:4.9.18
    container_name: poweradmin-4.4.3-pdns
    hostname: pdns
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
    volumes:
      - ./pdns.conf:/etc/powerdns/pdns.conf:ro
    ports:
      - "5311:53"
      - "5311:53/udp"
    networks: [pa-net]

volumes:
  db-data:

要点说明:

  • name: poweradmin-4.4.3-stack:显式指定项目名。注意 Compose 会把名称中的点替换掉,实际生成的网络名是 poweradmin-443-stack_pa-net,docker network ls 时按这个名字找;
  • db 的 healthcheck 用 MariaDB 官方镜像自带的 healthcheck.sh --connect --innodb_initialized,app 与 pdns 通过 depends_on: condition: service_healthy 等库就绪后再启动;
  • Web 端口映射为 8131:80:生产环境若 80 空闲可改回 80:80,或在前置 Nginx/Caddy 上做反向代理与 HTTPS 终结;
  • DNS 端口映射为 5311:53:服务器 53 端口常被系统解析服务占用,这里用高位端口演示,生产环境对外服务时改回 53:53 并放行 TCP/UDP。

2.3 pdns.conf 全文

local-address=0.0.0.0,::
launch=gmysql
gmysql-host=db
gmysql-port=3306
gmysql-user=poweradmin
gmysql-password=q1w2e3r4
gmysql-dbname=powerdns
gmysql-dnssec=yes
api=yes
webserver=yes
webserver-address=0.0.0.0
webserver-port=8081
api-key=pa-pdns-api-key-4.4.3
daemon=no

api-key 的值与 compose 中 PA_PDNS_API_KEY 保持一致——SQL 直连模式下 Poweradmin 在每次修改 DNSSEC 签名 zone 后要调用这个 API 触发 rectify,两边不一致时签名 zone 的 DNSSEC 维护会失败。

三、部署步骤

3.1 准备文件并启动

mkdir -p /opt/poweradmin && cd /opt/poweradmin
# 将 2.2、2.3 两节内容分别保存为 docker-compose.yml 与 pdns.conf 后:
docker compose up -d db app

app 首次启动会完成两件事:把 PowerDNS 的 gmysql 库结构灌入 powerdns 库(PA_INIT_PDNS_SCHEMA=true 触发),随后执行 Poweradmin 自身的数据迁移并创建管理员账号。启动日志(节选实测):

poweradmin-4.4.3-app  | {"level":"info","ts":...,"msg":"Poweradmin v4.4.3 starting..."}
poweradmin-4.4.3-app  | {"level":"info","ts":...,"msg":"Timezone set to: Asia/Shanghai"}
poweradmin-4.4.3-app  | {"level":"info","ts":...,"msg":"FrankenPHP handler started"}
poweradmin-4.4.3-app  | {"level":"info","ts":...,"msg":"Caddy server initialising"}
poweradmin-4.4.3-app  | {"level":"info","ts":...,"msg":"serving initial configuration"}

验证库结构初始化结果(实测回显):

docker exec poweradmin-4.4.3-db mariadb -upoweradmin -pq1w2e3r4 powerdns -e "SHOW TABLES;"
api_keys
comments
cryptokeys
domain_metadata
domains
groups
groups_perm_templ
log_api
log_groups
log_users
log_zones
login_attempts
migrations_user_group
perm_items
perm_templ
perm_templ_items
record_log
records
settings
supermasters
tsigkeys
user_agreements
user_groups
users
zones

其中 domains、records、cryptokeys 等 7 张表属于 PowerDNS gmysql 后端(由 PA_INIT_PDNS_SCHEMA 创建),其余 17 张属于 Poweradmin 自身(用户、权限模板、API key、各类审计日志等)。两套表同库但互不冲突,这正是 SQL 直连模式的库形态。

3.2 启动 PowerDNS 并确认健康

docker compose up -d pdns && sleep 5
docker compose ps --format '{{.Name}} {{.Status}}'
poweradmin-4.4.3-db    Up 2 minutes (healthy)
poweradmin-4.4.3-app   Up 2 minutes (healthy)
poweradmin-4.4.3-pdns  Up 8 seconds

PowerDNS 启动日志确认 gmysql 后端加载成功(实测节选):

poweradmin-4.4.3-pdns  | PowerDNS Authoritative Server 4.9.18 (C) 2001-2026 PowerDNS.COM BV
poweradmin-4.4.3-pdns  | gmysql Connection successful. Replication-based recursor is disabled.
poweradmin-4.4.3-pdns  | [webserver] Added & secured 'webserver' on 0.0.0.0:8081
poweradmin-4.4.3-pdns  | gmysql Backend launch complete: Launching gmysql backend
poweradmin-4.4.3-pdns  | Creating backend connection for TCP
poweradmin-4.4.3-pdns  | About to create 3 backend threads

⚠️ 排障实录(坑 1):若不挂载 pdns.conf,直接用命令行参数启动 pdns 服务,容器会崩溃重启,日志报错:

Fatal error: Trying to set unknown setting 'gsqlite3-dnssec'

根因:powerdns/pdns-auth-49:4.9.18 镜像自带一份 /etc/powerdns/pdns.conf,内容是 gsqlite3 示例配置且含一行无效的 gsqlite3-dnssec 标志位;命令行参数与配置文件会合并生效,配置文件里的非法行直接导致启动失败。解法就是本文做法——挂载一份干净的 pdns.conf 覆盖镜像默认配置文件。

3.3 首次登录

浏览器访问 http://<服务器IP>:8131/,会重定向到 /login 登录页,用 PA_ADMIN_USERNAME/PA_ADMIN_PASSWORD 设定的账号登录(本文示例:admin / q1w2e3r4)。登录成功后进入仪表盘。

⚠️ 排障实录(坑 2):镜像默认不创建任何管理员(docker logs 启动时会打印 Admin User Creation: false),不设 PA_CREATE_ADMIN: "true" 时 users 表为空,登录页永远提示凭据错误。这正是官方为避免「镜像一启动就有默认弱口令」做的设计:管理员账号必须显式声明创建。PA_CREATE_ADMIN=1 且未指定 PA_ADMIN_PASSWORD 时,镜像会生成随机密码并打印到日志。

四、功能验证:建 zone 与记录增删改

以下操作全部通过 Web 界面完成,辅以数据库与 dig 回显验证。

4.1 创建 master zone

登录后进入 Forward Zones → Add master zone,表单填写:

  • Zone name:example.com
  • Zone type:MASTER(下拉仅有 MASTER/NATIVE 两项)
  • Owner:勾选 admin
  • Zone template:none

提交后跳转 Forward Zones 列表,zone 出现在列表中。数据库侧验证(实测回显):

docker exec poweradmin-4.4.3-db mariadb -upoweradmin -pq1w2e3r4 powerdns -e \
  "SELECT id,name,type,master FROM domains; SELECT id,domain_id,name,type,ttl,content FROM records;"
id	name         type    master
1	example.com  MASTER  NULL

id	domain_id	name         type  ttl     content
1	1         example.com  SOA   86400   ns1.example.com hostmaster.example.com 2026102600 28800 7200 604800 86400

SOA 记录由 Poweradmin 按 DNS_NS1/DNS_NS2/DNS_HOSTMASTER 环境变量自动生成,serial 为创建当日日期格式 2026102600。

4.2 添加记录(A / MX / TXT)

进入 zone 编辑页(Forward Zones → example.com),在记录添加表单中依次提交三条记录,每次提交后 SOA serial 自动加 1:

NameTypeContentPrioTTL
wwwA198.51.100.10086400
(空 = 本域)MXmail.example.com1086400
(空 = 本域)TXT"v=spf1 -all"086400

⚠️ 排障实录(坑 3):TXT 记录内容必须自带引号。填 v=spf1 -all(不带引号)提交会被表单校验拒绝,页面提示:

TXT record content must be enclosed in quotes.

这是 Poweradmin 的显式校验而非 PowerDNS 的行为——引号是 zone 文件语法的一部分,面板要求录入者直接按 zone 文件格式书写。

添加完成后的库内状态(实测回显):

id	name             type  content
1	example.com      SOA   ns1.example.com hostmaster.example.com 2026102602 28800 7200 604800 86400
2	www.example.com  A     198.51.100.10
3	example.com      MX    mail.example.com

4.3 修改记录

在 zone 编辑页把 www.example.com 的 A 记录内容从 198.51.100.10 改为 198.51.100.11,点 Save changes 提交。保存后库内即变为新值,SOA serial 同步递增。

4.4 删除记录

勾选 TXT 记录行,点 Delete selected。

⚠️ 排障实录(坑 4):删除是两步确认流——第一次提交后进入「Are you sure you want to delete the selected records?」确认页,必须再点一次确认按钮(confirm=1)才真正删除,直接丢弃确认页会导致记录仍在。这是防误删设计,脚本化操作时容易在第一步就以为已删完。

删除成功后跳回编辑页,TXT 行消失,SOA serial 继续递增。

4.5 dig 验证生效闭环

在服务器上对映射端口 5311 发起查询(实测回显):

dig @127.0.0.1 -p 5311 www.example.com A +noedns
; <<>> DiG 9.20.30 <<>> @127.0.0.1 -p 5311 www.example.com A +noedns
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48740
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;www.example.com.		IN	A

;; ANSWER SECTION:
www.example.com.	86400	IN	A	198.51.100.11

;; Query time: 2 msec
;; SERVER: 127.0.0.1#5311(127.0.0.1) (UDP)
;; WHEN: Sun Oct 26 06:45:31 UTC 2026
;; MSG SIZE  rcvd: 49

注意 ANSWER 里的 198.51.100.11——正是 4.3 节修改后的值,说明面板改动实时生效、无缓存延迟(PowerDNS 每次查询直读数据库)。再验证 MX、SOA 与已删除的 TXT:

dig @127.0.0.1 -p 5311 example.com MX +noedns | grep -A3 "ANSWER SECTION"
dig @127.0.0.1 -p 5311 example.com SOA +noedns | grep -A2 "ANSWER SECTION"
dig @127.0.0.1 -p 5311 example.com TXT +noedns | grep -E "status:|ANSWER"
;; ANSWER SECTION:
example.com.		86400	IN	MX	10 mail.example.com.

;; ANSWER SECTION:
example.com.		86400	IN	SOA	ns1.example.com. hostmaster.example.com. 2026102605 28800 7200 604800 86400

;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 26734
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0

SOA serial 2026102605 是四次修改累计递增的结果;TXT 查询 ANSWER: 0 证明删除已生效。flags: qr aa rd 中的 aa(Authoritative Answer)确认这是权威应答。

4.6 健全性检查:apex NS 记录

⚠️ 排障实录(坑 5):Poweradmin 创建 master zone 时只生成 SOA,不自动创建 apex NS 记录。用 PowerDNS 自带的 pdnsutil check-zone 检查(实测回显):

docker exec poweradmin-4.4.3-pdns pdnsutil check-zone example.com
[Error] No NS record at zone apex in zone 'example.com'
Checked 3 records of 'example.com', 1 errors, 0 warnings.

缺少 apex NS 时 DNS 查询仍能应答,但授权链不完整(从父域 delegation 过来的查询会被部分解析器拒绝)。解法:在 zone 编辑页为 example.com 本域补两条 NS 记录(ns1.example.com、ns2.example.com),补齐后复查:

Checked 5 records of 'example.com', 0 errors, 0 warnings.

生产部署建议把「建 zone 后立即补 apex NS」写进操作清单,或改用 zone template(DNS_NS1/DNS_NS2 环境变量只影响 SOA,不生成 NS)。

五、安装向导说明

Poweradmin 传统源码部署(tarball 解压 + PHP 运行时)带一个 8 步 Web 安装向导,官方文档(docs.poweradmin.org → Installation → Web installer wizard)描述的流程为:

  1. Prerequisites:文件/目录权限自检(config 目录可写等);
  2. Configuration check:PHP 扩展与版本检查;
  3. Language:选择界面语言;
  4. Database:填写数据库主机、库名、账号,并设置管理员账号密码(用户名固定 admin);
  5. DNS defaults:hostmaster 邮箱、ns1/ns2 默认 NS,并生成受限数据库用户的创建 SQL;
  6. Create limited user:展示第 4 步生成的 SQL,提示手动在数据库执行(向导刻意不用高权限账号直接建用户);
  7. Generate config:生成 config/settings.php 内容,提示手动复制到 config 目录;
  8. Remove installer:删除 install/ 目录后进入登录页。

本文的 Docker 镜像部署没有这个向导——实测把运行中实例的 config/settings.php 移除后访问首页只会得到「No configuration file found at config/settings.php」错误页,错误页里的 installer 超链接是遗留文案,点开仍是同一错误页;/install 与 /install/ 均不返回向导界面。官方 Docker 镜像的初始化完全由环境变量驱动(DB_TYPE 必填,缺了连启动都会被 entrypoint 拒绝),表结构与账号自动创建。两种路径的选择建议:生产/可重复部署用环境变量方式(本篇做法);追求「逐步确认」的一次性手工部署再考虑源码 + 向导方式。

六、等价 docker run 命令

不用 Compose 时,以下三条命令与 2.2 节编排等价(同一网络,先建网络):

docker network create -d bridge --subnet 10.89.60.0/24 pa-net

docker run -d --name poweradmin-4.4.3-db --network pa-net \
  -e MARIADB_ROOT_PASSWORD=q1w2e3r4 \
  -e MARIADB_DATABASE=powerdns \
  -e MARIADB_USER=poweradmin \
  -e MARIADB_PASSWORD=q1w2e3r4 \
  -v poweradmin-db-data:/var/lib/mysql \
  mariadb:10.11

docker run -d --name poweradmin-4.4.3-app --network pa-net \
  -p 8131:80 \
  -e DB_TYPE=mysql -e DB_HOST=poweradmin-4.4.3-db -e DB_PORT=3306 \
  -e DB_USER=poweradmin -e DB_PASS=q1w2e3r4 -e DB_NAME=powerdns \
  -e PA_INIT_PDNS_SCHEMA=true \
  -e DNS_NS1=ns1.example.com -e DNS_NS2=ns2.example.com \
  -e DNS_HOSTMASTER=hostmaster.example.com \
  -e PA_PDNS_API_URL=http://poweradmin-4.4.3-pdns:8081 \
  -e PA_PDNS_API_KEY=pa-pdns-api-key-4.4.3 \
  -e PA_API_ENABLED=true -e PA_API_DOCS_ENABLED=true \
  -e PA_SESSION_KEY=pa-4.4.3-session-key-0123456789abcdefXYZ \
  -e PA_TIMEZONE=Asia/Shanghai \
  -e PA_CREATE_ADMIN=true -e PA_ADMIN_USERNAME=admin -e PA_ADMIN_PASSWORD=q1w2e3r4 \
  poweradmin/poweradmin:4.4.3

docker run -d --name poweradmin-4.4.3-pdns --network pa-net \
  -p 5311:53 -p 5311:53/udp \
  -v /opt/poweradmin/pdns.conf:/etc/powerdns/pdns.conf:ro \
  powerdns/pdns-auth-49:4.9.18

注意两点差异:直连 docker run 没有 Compose 的健康检查等待,app/pdns 需等数据库完全就绪后启动(建议库先起、间隔 10 秒以上再起其余两个);pdns.conf 里的 gmysql-host 要相应改成 poweradmin-4.4.3-db 这个容器名(Compose 内服务名是 db)。

七、常用运维命令

# 栈状态与日志
docker compose ps
docker compose logs -f app pdns

# zone 健全性检查与查看(PowerDNS 侧权威工具)
docker exec poweradmin-4.4.3-pdns pdnsutil check-zone example.com
docker exec poweradmin-4.4.3-pdns pdnsutil list-zone example.com
docker exec poweradmin-4.4.3-pdns pdnsutil show-zone example.com

list-zone 输出为 zone 文件格式(实测节选),可直接用于核对记录:

$ORIGIN .
example.com	86400	IN	MX	10 mail.example.com.
example.com	86400	IN	SOA	ns1.example.com hostmaster.example.com 2026102610 28800 7200 604800 86400
www.example.com	86400	IN	A	198.51.100.11

show-zone 可看 zone 角色与 DNSSEC 状态:

This is a Master zone
Last SOA serial number we notified: 0 != 2026102610 (serial in the database)
Zone is not actively secured
Metadata items: None
No keys for zone 'example.com'.

数据备份(整库导出即可覆盖两套表):

docker exec poweradmin-4.4.3-db sh -c \
  'mariadb-dump -upoweradmin -pq1w2e3r4 powerdns' > powerdns-$(date +%F).sql

升级:4.4 LTS 线内的补丁升级(如 4.4.2 → 4.4.3)无需数据库迁移,改 compose 中镜像 tag 后 docker compose up -d app 重建即可;跨大版本(如 4.4 → 4.5)前先看官方发布说明中的迁移提示。

八、常见问题速查

现象根因与解法本文位置
pdns 反复重启,报 Trying to set unknown setting 'gsqlite3-dnssec'镜像自带 gsqlite3 示例配置非法;挂载干净 pdns.conf 覆盖2.3 / 3.2
登录页凭据永远错误未设 PA_CREATE_ADMIN,users 表为空3.3
页面报 Session encryption key is too short, please set a longer one in your configuration file.PA_SESSION_KEY 少于 32 字符(实测 29 字符被拒),换 ≥32 字符随机串2.2
TXT 记录提交被拒 TXT record content must be enclosed in quotes.TXT 内容需自带英文双引号4.2
脚本直 POST 建 zone 报 Invalid or unexpected input given.dom_type 必须用大写 MASTER/NATIVE(与 UI 下拉一致),小写被拒4.1
pdnsutil check-zone 报 No NS record at zone apex建 zone 不自动生成 apex NS,手动补 NS 记录4.6
删除记录后列表里还在两步确认流,需在确认页再提交一次4.4
docker pull 官方镜像缓慢国内环境可为镜像名加加速前缀(如 hub.rat.dev/poweradmin/poweradmin:4.4.3)一

九、参考链接

  • Poweradmin 官方 Docker 文档(仓库 DOCKER.md):https://github.com/poweradmin/poweradmin/blob/master/DOCKER.md
  • 官方安装文档(含 8 步向导说明):https://docs.poweradmin.org/installation/
  • PowerDNS Authoritative 官方文档:https://doc.powerdns.com/authoritative/
  • 同专栏认知篇:《Poweradmin v4.4.3 介绍与选型指南》