什么是PowerDNS

PowerDNS(PDNS)成立于20世纪90年代末,是开源DNS软件、服务和支持的主要供应商,它们提供的权威认证DNS服务器和递归认证DNS服务器都是100%开源的软件,同时也和红帽等开源方案提供商一样提供了付费的技术支持版本。同时官方表示为了避免和软件使用者出现竞争,他们只提供服务支持而不提供DNS托管服务。

和其他的如BINDdnsmasq等将这些功能集成到一起的DNS软件不同,PowerDNS将其一分为二,分为了PowerDNS Authoritative ServerPowerDNS Recursor,分别对应这两种主要的需求,而我们常说的pdns指的就是PowerDNS Authoritative Server (后面简称PDNS Auth),主要用途就是作为权威域名服务器,当然也可以作为普通的DNS服务器提供DNS查询功能,但是自定义域名解析列表没有记录的域名则直接丢弃,不做解析,此时就需要结合PowerDNS-Recursor使用了。

对于PowerDNS-RecursorPowerDNS官网介绍其是一个内置脚本能力的高性能的DNS递归查询服务器,并且已经为一亿五千万个互联网连接提供支持。

PowerDNS Authoritative Server官方文档
PowerDNS Authoritative Server — PowerDNS Authoritative Server documentation

PowerDNS Recursor官方文档
PowerDNS Recursor — PowerDNS Recursor documentation


部署规划

  • 我们公司内网有多个VLAN,所以不同网段其实是打通的。
  • 请根据实际情况分配IP地址。
系统 主机名 IP地址 服务 作用
Centos7.9 nameserver-sr1-871 10.200.1.153 PowerDNS Authoritative Server Mater DNS
Centos7.9 nameserver-sr2-872 10.200.1.154 PowerDNS Authoritative Server Slave DNS
Centos7.9 nameserver-rs1-860 172.16.8.30 PowerDNS Recursor DNS1
Centos7.9 nameserver-rs2-861 172.16.8.31 PowerDNS Recursor DNS2

准备工作

  • 4台服务器均需要操作
# 安装一些包
yum install -y epel-release

sed -e 's|^mirrorlist=|#mirrorlist=|g' \
         -e 's|^#baseurl=http://mirror.centos.org/centos|baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos|g' \
         -i.bak \
         /etc/yum.repos.d/CentOS-*.repo

sed -e 's!^metalink=!#metalink=!g' \
    -e 's!^#baseurl=!baseurl=!g' \
    -e 's!http://download\.fedoraproject\.org/pub/epel!https://mirrors.tuna.tsinghua.edu.cn/epel!g' \
    -e 's!http://download\.example/pub/epel!https://mirrors.tuna.tsinghua.edu.cn/epel!g' \
    -i /etc/yum.repos.d/epel*.repo

yum install -y chrony conntrack ipvsadm ipset jq iptables curl sysstat libseccomp wget socat git gcc-c++ make yum-utils testice-mapper-persistent-data lvm2 bash-completion nfs-utils lrzsz

# 关闭防火墙
systemctl stop firewalld && systemctl disable firewalld
systemctl stop iptables && systemctl disable iptables

# 关闭 Selinux
setenforce 0 && sed -i 's/SELINUX=.*/SELINUX=disabled/g' /etc/selinux/config

# 时间同步
(crontab -l;echo '*/30 * * * * /usr/sbin/ntpdate ntp1.aliyun.com && /usr/sbin/hwclock -w') | crontab

# 内核优化
echo "* - nofile 65535" >> /etc/security/limits.conf
echo "* - nproc 65536" >> /etc/security/limits.conf
sed -i 's#4096#65536#g' /etc/security/limits.d/20-nproc.conf

cat >> /etc/security/limits.d/nofile.conf <<EOF
* soft nofile 65536
* hard nofile 65536
EOF

cat >> /etc/sysctl.conf <<EOF
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 20480
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 2
net.core.somaxconn = 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_max_tw_buckets = 10240
net.ipv4.ip_forward = 1
net.ipv4.tcp_tw_recycle = 0
net.ipv4.neigh.default.gc_thresh1 = 1024
net.ipv4.neigh.default.gc_thresh1 = 2048
net.ipv4.neigh.default.gc_thresh1 = 4096
vm.swappiness = 0
vm.overcommit_memory = 1
vm.panic_on_oom = 0
fs.inotify.max_user_instances = 8192
fs.inotify.max_user_watches = 1048576
fs.file-max = 52706963
fs.nr_open = 52706963
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 10
EOF

sysctl -p >/dev/null 2>&1

# 安装 docker
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
sed -i 's+download.docker.com+mirrors.aliyun.com/docker-ce+' /etc/yum.repos.d/docker-ce.repo
yum makecache fast
yum -y install docker-ce

# 更新系统
yum update -y

# 重启系统
init 6

部署PowerDNS Authoritative Server

  • Mater DNSSlave DNS上安装PowerDNS Authoritative Server

SQL 初始化语句模板地址
Generic MySQL backend — PowerDNS Authoritative Server documentation

# 安装 PowerDNS Authoritative Server
yum install -y epel-release yum-plugin-priorities &&
curl -o /etc/yum.repos.d/powerdns-auth-48.repo https://repo.powerdns.com/repo-files/el-auth-48.repo &&
yum install -y pdns pdns-backend-mysql.x86_64 mariadb-server

# 连接 mariadb 并配置
systemctl start mariadb
systemctl enable mariadb
mysql -uroot

# 执行以下初始化 sql 语句
create DATABASE pdns;

grant all privileges on pdns.* to pdns@localhost identified by 'pdns';

flush privileges;

use pdns;

CREATE TABLE domains (
  id                    INT AUTO_INCREMENT,
  name                  VARCHAR(255) NOT NULL,
  master                VARCHAR(128) DEFAULT NULL,
  last_check            INT DEFAULT NULL,
  type                  VARCHAR(8) NOT NULL,
  notified_serial       INT UNSIGNED DEFAULT NULL,
  account               VARCHAR(40) CHARACTER SET 'utf8' DEFAULT NULL,
  options               VARCHAR(64000) DEFAULT NULL,
  catalog               VARCHAR(255) DEFAULT NULL,
  PRIMARY KEY (id)
) Engine=InnoDB CHARACTER SET 'latin1';

CREATE UNIQUE INDEX name_index ON domains(name);
CREATE INDEX catalog_idx ON domains(catalog);


CREATE TABLE records (
  id                    BIGINT AUTO_INCREMENT,
  domain_id             INT DEFAULT NULL,
  name                  VARCHAR(255) DEFAULT NULL,
  type                  VARCHAR(10) DEFAULT NULL,
  content               VARCHAR(64000) DEFAULT NULL,
  ttl                   INT DEFAULT NULL,
  prio                  INT DEFAULT NULL,
  disabled              TINYINT(1) DEFAULT 0,
  ordername             VARCHAR(255) BINARY DEFAULT NULL,
  auth                  TINYINT(1) DEFAULT 1,
  PRIMARY KEY (id)
) Engine=InnoDB CHARACTER SET 'latin1';

CREATE INDEX nametype_index ON records(name,type);
CREATE INDEX domain_id ON records(domain_id);
CREATE INDEX ordername ON records (ordername);


CREATE TABLE supermasters (
  ip                    VARCHAR(64) NOT NULL,
  nameserver            VARCHAR(255) NOT NULL,
  account               VARCHAR(40) CHARACTER SET 'utf8' NOT NULL,
  PRIMARY KEY (ip, nameserver)
) Engine=InnoDB CHARACTER SET 'latin1';


CREATE TABLE comments (
  id                    INT AUTO_INCREMENT,
  domain_id             INT NOT NULL,
  name                  VARCHAR(255) NOT NULL,
  type                  VARCHAR(10) NOT NULL,
  modified_at           INT NOT NULL,
  account               VARCHAR(40) CHARACTER SET 'utf8' DEFAULT NULL,
  comment               TEXT CHARACTER SET 'utf8' NOT NULL,
  PRIMARY KEY (id)
) Engine=InnoDB CHARACTER SET 'latin1';

CREATE INDEX comments_name_type_idx ON comments (name, type);
CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);


CREATE TABLE domainmetadata (
  id                    INT AUTO_INCREMENT,
  domain_id             INT NOT NULL,
  kind                  VARCHAR(32),
  content               TEXT,
  PRIMARY KEY (id)
) Engine=InnoDB CHARACTER SET 'latin1';

CREATE INDEX domainmetadata_idx ON domainmetadata (domain_id, kind);


CREATE TABLE cryptokeys (
  id                    INT AUTO_INCREMENT,
  domain_id             INT NOT NULL,
  flags                 INT NOT NULL,
  active                BOOL,
  published             BOOL DEFAULT 1,
  content               TEXT,
  PRIMARY KEY(id)
) Engine=InnoDB CHARACTER SET 'latin1';

CREATE INDEX domainidindex ON cryptokeys(domain_id);


CREATE TABLE tsigkeys (
  id                    INT AUTO_INCREMENT,
  name                  VARCHAR(255),
  algorithm             VARCHAR(50),
  secret                VARCHAR(255),
  PRIMARY KEY (id)
) Engine=InnoDB CHARACTER SET 'latin1';

CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm);

quit;
  • Mater DNSSlave DNS上配置PowerDNS Authoritative Server

Mater DNS

# 编辑 PowerDNS Authoritative Server 配置文件
cp /etc/pdns/pdns.conf /etc/pdns/pdns.conf.default
cat /dev/null > /etc/pdns/pdns.conf

# Mater DNS 的配置
vim /etc/pdns/pdns.conf
# 运行模式,no 为非守护进程模式,yes 为守护进程模式
daemon=no
# guardian 进程的启用状态
guardian=no
# 设置运行时的组和用户 ID
setgid=pdns
setuid=pdns
# 日志级别,数值越高,日志越详细
loglevel=9
# 日志记录设施
logging-facility=0
# 缓存 TTL(生存时间)值
cache-ttl=60
# 查询缓存和负查询缓存的 TTL 值
query-cache-ttl=60
negquery-cache-ttl=60
# 分配器和接收器线程数,我的服务器是 4核4线程,仅供参考
distributor-threads=4
receiver-threads=4
# 允许端口重用
reuseport=yes
# 启动的后端类型
launch=gmysql
# MySQL 数据库连接配置
gmysql-host=127.0.0.1
gmysql-dbname=pdns
gmysql-user=pdns
gmysql-password=pdns
# 本地监听地址和端口
local-address=0.0.0.0
local-port=53
# API 的启用及 API 密钥
api=yes
api-key=ITsupport.0
# Web 服务器配置
webserver=yes
webserver-address=0.0.0.0
webserver-allow-from=0.0.0.0/0
webserver-port=8081
webserver-loglevel=detailed
# 设为主服务器
master=yes
# 通知其他服务器地址,这个是 Slave DNS IP
also-notify=10.200.1.154
# 控制AXFR(区域传输)的IP地址范围和禁用状态
allow-axfr-ips=0.0.0.0/0
disable-axfr=no
# 允许从哪些 IP 进行 DNS 更新
allow-dnsupdate-from=0.0.0.0/0
# 从服务器周期检查间隔
slave-cycle-interval=60
# 日志级别,数值越高,日志越详细
loglevel=9


# 配置日志记录
vim /etc/rsyslog.conf
# 底部新增
local0.info    /var/log/pdns/pdns.info.log
local0.warn    /var/log/pdns/pdns.warn.log
local0.err    /var/log/pdns/pdns.err.log

# 授权并手工创建 log 文件
mkdir -p /var/log/pdns
touch /var/log/pdns/pdns.info.log
touch /var/log/pdns/pdns.warn.log
touch /var/log/pdns/pdns.err.log
chmod -R 755 /etc/pdns/pdns.conf /var/log/pdns/

# 启动 Mater DNS
systemctl start pdns
systemctl enable pdns
systemctl restart rsyslog

# 修改启动文件
vim /usr/lib/systemd/system/pdns.service
#ExecStart=/usr/sbin/pdns_server --socket-dir=%t/pdns --guardian=no --daemon=no --disable-syslog --log-timestamp=no --write-pid=no
ExecStart=/usr/sbin/pdns_server --socket-dir=%t/pdns

# 重启 PowerDNS Authoritative Server
systemctl daemon-reload && systemctl restart pdns

Slave DNS

# 编辑 PowerDNS Authoritative Server 配置文件
cp /etc/pdns/pdns.conf /etc/pdns/pdns.conf.default
cat /dev/null > /etc/pdns/pdns.conf

# Slave DNS 的配置
vim /etc/pdns/pdns.conf
# 运行模式,no 为非守护进程模式,yes 为守护进程模式
daemon=no
# guardian 进程的启用状态
guardian=no
# 设置运行时的组和用户 ID
setgid=pdns
setuid=pdns
# 日志级别,数值越高,日志越详细
loglevel=9
# 日志记录设施
logging-facility=0
# 缓存 TTL(生存时间)值
cache-ttl=60
# 查询缓存和负查询缓存的 TTL 值
query-cache-ttl=60
negquery-cache-ttl=60
# 分配器和接收器线程数,我的服务器是 4核4线程,仅供参考
distributor-threads=4
receiver-threads=4
# 允许端口重用
reuseport=yes
# 启动的后端类型
launch=gmysql
# MySQL 数据库连接配置
gmysql-host=127.0.0.1
gmysql-dbname=pdns
gmysql-user=pdns
gmysql-password=pdns
# 本地监听地址和端口
local-address=0.0.0.0
local-port=53
# API 的启用及 API 密钥
api=yes
api-key=ITsupport.0
# Web 服务器配置
webserver=yes
webserver-address=0.0.0.0
webserver-allow-from=0.0.0.0/0
webserver-port=8081
webserver-loglevel=detailed
# 通知其他服务器地址,这个是 Mater DNS IP
also-notify=10.200.1.153
# 控制AXFR(区域传输)的IP地址范围和禁用状态
allow-axfr-ips=0.0.0.0/0
# 允许从哪些 IP 进行 DNS 更新
allow-dnsupdate-from=0.0.0.0/0
# 设为 Slave DNS
slave=yes
# 指定 Mater DNS
master=10.200.1.153

# 配置日志记录
vim /etc/rsyslog.conf
# 底部新增
local0.info    /var/log/pdns/pdns.info.log
local0.warn    /var/log/pdns/pdns.warn.log
local0.err    /var/log/pdns/pdns.err.log

# 授权并手工创建 log 文件
mkdir -p /var/log/pdns
touch /var/log/pdns/pdns.info.log
touch /var/log/pdns/pdns.warn.log
touch /var/log/pdns/pdns.err.log
chmod -R 755 /etc/pdns/pdns.conf /var/log/pdns/

# 启动 Mater DNS
systemctl start pdns
systemctl enable pdns
systemctl restart rsyslog

# 修改启动文件
vim /usr/lib/systemd/system/pdns.service
#ExecStart=/usr/sbin/pdns_server --socket-dir=%t/pdns --guardian=no --daemon=no --disable-syslog --log-timestamp=no --write-pid=no
ExecStart=/usr/sbin/pdns_server --socket-dir=%t/pdns

# 重启 PowerDNS Authoritative Server
systemctl daemon-reload && systemctl restart pdns
  • Mater DNSSlave DNS上部署web管理控制台
# 启动 docker
systemctl start docker && systemctl enable docker

# 部署 powerdnsadmin
# SECRET_KEY 随意
mkdir -p /data/powerdnsadmin && chmod 777 /data/powerdnsadmin
docker run -itd --restart=always \
  -e SECRET_KEY='ITsupport.0' \
  -v /data/powerdnsadmin:/data \
  -p 80:80 \
  powerdnsadmin/pda-legacy:latest
  • 浏览器直接访问Mater DNSSlave DNS IP地址配置PowerDNS-Admin

注意区分Mater DNSSlave DNS IP地址,我的图片实例只有Mater DNS的配置

image.png

image.png

image.png

  • 配置域名解析,测试主从同步

Mater DNS web界面配置

image.png

image.png

image.png

image.png

image.png

image.png

image.png

Slave DNS web界面配置

image.png

image.png

等待60秒后,Mater DNS的解析记录会同步到Slave DNS
我们在Slave DNS上查看是否正常同步

image.png

image.png

可以见到,Mater DNS的解析记录已经自动同步到Slave DNS
至此,PowerDNS Authoritative Server部署完成,并且做了主从(主备)!


部署PowerDNS-Recursor

  • DNS1DNS2上安装PowerDNS-Recursor
# 安装 PowerDNS-Recursor
yum install -y epel-release yum-plugin-priorities &&
curl -o /etc/yum.repos.d/powerdns-rec-49.repo https://repo.powerdns.com/repo-files/el-rec-49.repo &&
yum install -y pdns-recursor
  • DNS1DNS2上配置PowerDNS-Recursor
# 编辑 DNS1 和 DNS2 配置文件
cp /etc/pdns-recursor/recursor.conf /etc/pdns-recursor/recursor.conf.bak
cat /dev/null > /etc/pdns-recursor/recursor.conf

vim /etc/pdns-recursor/recursor.conf
# 运行 PowerDNS Recursor 作为守护进程
daemon=yes
# 监听所有的 IP 地址
local-address=0.0.0.0
# 允许所有 IP 地址的查询
allow-from=0.0.0.0/0
# 在端口53上监听 DNS 查询
local-port=53
# 将所有查询转发到指定的 DNS 服务器
forward-zones-recurse=.=223.5.5.5;202.96.128.86;119.29.29.29
# 从文件加载转发区域的配置
forward-zones-file=/etc/pdns-recursor/zones
# 缓存中的最大记录数
max-cache-entries=800000
# 负缓存条目的最大生存时间(TTL)
max-negative-ttl=10
# 在日志条目中包含时间戳
log-timestamp=yes
# 日志级别
loglevel=6
# 运行进程的组和用户身份
setgid=pdns-recursor
setuid=pdns-recursor
# 禁用 DNSSEC,非特殊情况都请禁用
dnssec=off
# 启用并配置内置的 web 服务器,用于 API 和监控
webserver=yes
webserver-address=0.0.0.0
webserver-port=8081
webserver-allow-from=0.0.0.0/0
api-key=ITsupport.0
# 日志记录设施
logging-facility=1
# 详细日志,必要时可以开起来
#trace=yes
# 使用4个线程
threads=4
# 允许的最大同时查询线程数,看需求
#max-mthreads=4
# 禁用查询分发
pdns-distributes-queries=no
# 启用 SO_REUSEPORT,允许多个进程/线程共享同一个端口
reuseport=yes
# 将线程绑定到特定的 CPU 核心
cpu-map=0=0 1=1 2=2 3=3

# 编写 DNS1 和 DNS2 转发区域
# 可以理解为哪些域转发到内部的权威 DNS 解析服务器
vim /etc/pdns-recursor/zones
# 后面两个 IP 为 `Mater DNS`和 `Slave DNS` 地址
+itwordsweb.net=10.200.1.153;10.200.1.154

# 修改 DNS1 和 DNS2 启动文件
vim /usr/lib/systemd/system/pdns-recursor.service
#ExecStart=/usr/sbin/pdns_recursor --socket-dir=%t/pdns-recursor --daemon=no --write-pid=no --disable-syslog --log-timestamp=no
ExecStart=/usr/sbin/pdns_recursor --socket-dir=%t/pdns-recursor --daemon=no --write-pid=no

# 配置 DNS1 和 DNS2 日志记录
vim /etc/rsyslog.conf
# 底部新增
local1.info  /var/log/pdns/pdns-recursor.info.log
local1.warn  /var/log/pdns/pdns-recursor.warn.log
local1.err  /var/log/pdns/pdns-recursor.err.log

# DNS1 和 DNS2 授权并手工创建 log 文件
mkdir -p /var/log/pdns
touch /var/log/pdns/pdns-recursor.info.log
touch /var/log/pdns/pdns-recursor.warn.log
touch /var/log/pdns/pdns-recursor.err.log
chmod -R 755 /etc/pdns-recursor/recursor.conf /etc/pdns-recursor/zones /var/log/pdns/

# 启动服务
systemctl daemon-reload && systemctl restart rsyslog
systemctl enable pdns-recursor && systemctl start pdns-recursor
  • 本地电脑配置DNS服务器为DNS1DNS2的地址

image.png

  • 测试是否生效

image.png

通过测试可见,DNS服务器已经被识别为DNS1的地址,并且访问 www.baidu.com 时正常返回,访问 www.itwordsweb.net 时会被转发。

  • 模拟DNS1宕机,测试一下
# DNS1上把pdns-recursor停止
systemctl stop pdns-recursor
  • 继续测试

image.png

可以看到,当DNS1宕机,DNS2会正常接管DNS解析服务。
至此,整套PowerDNS,包含PowerDNS Authoritative ServerPowerDNS-Recursor部署完成,并测试通过!


文章作者: Runfa Li
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Linux 小白鼠
Linux 网络 Linux 网络 dns解析 权威dns 递归dns DNS服务器 开源DNS dns 域名解析 powerdns
觉得文章不错,打赏一点吧,1分也是爱~
打赏
微信 微信
支付宝 支付宝