环境:Ubuntu 20.04
PowerDNS 提供的三个产品 Authoritative Server、Recursor、dnsdist 可以分别用做权威DNS、递归DNS和DNS负载均衡,这里使用第一个。
安装
先停止占用 53 端口的服务
systemctl disable systemd-resolved
systemctl stop systemd-resolved
然后编辑/etc/resolv.conf
,按如下注释掉本地服务地址,添加一条公共 DNS,这样才能恢复本地域名解析服务。
#nameserver 127.0.0.53
nameserver 223.6.6.6
PDNS
sudo apt update
sudo apt install -y curl gnupg2 software-properties-common
curl -fsSL https://repo.powerdns.com/FD380FBB-pub.asc | sudo tee /etc/apt/trusted.gpg.d/powerdns.asc
echo "deb [arch=amd64] http://repo.powerdns.com/ubuntu focal-auth-44 main" | sudo tee /etc/apt/sources.list.d/powerdns.list
sudo apt update
sudo apt install -y pdns-server
查看版本,确保在 4.x 及以上
pdns_server --version
PowerDNS Authoritative Server 4.4.3 (C) 2001-2020 PowerDNS.COM BV
建议参考文章底部链接,使用官方推荐安装最新稳定版本。
配置 MySQL 作为后端
安装后端
apt install -y pdns-backend-mysql
添加配置,编辑/etc/powerdns/pdns.conf
launch=gmysql
gmysql-host=localhost
gmysql-port=3306
gmysql-user=pdns
gmysql-password=yourpassword
gmysql-dbname=pdns
这里使用 launch 参数配置 pdns 后端(Backend)数据库。虽然可以使用 += 语法增量配置,例如:launch+=bind 配置多一个 bind 作为后端,配置了多个后端会同时加载,先加载成功的默认作为主后端,其他作为备用,所有后端的配置需要相同才有意义。因此不管配置了多少个后端,使用上还是只有一个,建议只配置一个就可以了,主备功能还是建议直接使用第三个 dnsdist 产品。
搭配 MySQL
前面配置了 mysql 作为后端数据库,所以需要安装和创建对应的数据库和用户。
sudo apt install -y mariadb-server
sudo systemctl enable --now mariadb
登录 mysql
mysql -u root -p
创建 pdns 数据库并授权 pdns 用户
CREATE DATABASE pdns;
GRANT ALL ON pdns.* TO 'pdns'@'localhost' IDENTIFIED BY 'yourpassword';
FLUSH PRIVILEGES;
EXIT;
导入 PowerDNS 所需的数据库表
mysql -u pdns -p pdns < /usr/share/pdns-backend-mysql/schema/schema.mysql.sql
验证域名解析
查询结果正常返回“status: REFUSED”,因为不存在该域名记录。
dig a www.example.com @127.0.0.1
使用 pdnsutil 工具添加些记录,然后再尝试查询。
sudo -u pdns pdnsutil create-zone example.com ns1.example.com
sudo -u pdns pdnsutil add-record example.com '' MX '25 mail.example.com'
sudo -u pdns pdnsutil add-record example.com. www A 192.0.2.1
dig +short www.example.com @127.0.0.1
建议使用 pdnsutil 工具进行区域配置等操作,而不是直接操作数据库,它能对添加的配置进行检查和验证,确保不会产生问题。
现在可以进一步编辑区域,添加更多的配置。
pdnsutil edit-zone example.com
报错
pdns_server[2043790]: Fatal error: Trying to set unknown parameter 'ecs-add-for'
pdns_server[2046447]: Fatal error: Trying to set unknown parameter 'ecs-scope-mask'
尝试添加上面两个参数到配置文件时报错,因为这些参数是和 PowerDNS Recursor (作为递归DNS)扩展模块 ECS (EDNS Client Subnet) 一起使用的。ECS 是 DNS 扩展的一部分,用于在 DNS 查询中传递客户端的 IP 地址的子网信息,这通常用于更准确的地理定位和内容分发。
因此,使用 MySQL 作为 pdns 后端,常用于作为单纯的权威DNS来使用。
配置 GeoIP 作为后端
PowerDNS 可以使用 geoip 作为后端,允许基于 MaxMind GeoIP 数据库进行地理位置解析,并结合 ECS(EDNS Client Subnet),返回基于客户端 IP 位置的最优解析结果。
安装
apt install -y pdns-backend-geoip geoip-bin geoip-database
下载 GeoLite2 数据库
mkdir -p /var/lib/GeoIP
cd /var/lib/GeoIP
# 下载 GeoLite2 数据库(需要 MaxMind 账户和 License Key,到官网先注册再创建 License Key,也可以不创建直接下载数据库文件并上传解压)
wget "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City&license_key=Your_License_Key&suffix=tar.gz" -O GeoLite2-City.tar.gz
# 解压
tar -xzf GeoLite2-City.tar.gz --strip-components=1
安装 mmdb 工具验证 GeoLite2 数据库可用性
apt install -y mmdb-bin
mmdblookup --file /var/lib/GeoIP/GeoLite2-City.mmdb --ip 8.8.8.8
配置文件
配置 /etc/powerdns/pdns.conf
#################################
# local-address Local IP addresses to which we bind
#
local-address=0.0.0.0:53
#################################
# include-dir Include *.conf files from this directory
#
# include-dir=
include-dir=/etc/powerdns/pdns.d
#################################
# log-dns-details If PDNS should log DNS non-erroneous details
#
log-dns-details=yes
#################################
# log-dns-queries If PDNS should log all incoming DNS queries
#
log-dns-queries=yes
#################################
# log-timestamp Print timestamps in log lines
#
log-timestamp=yes
#################################
# logging-facility Log under a specific facility
#
#logging-facility=0
#################################
# loglevel Amount of logging. Higher is more. Do not set below 3
#
loglevel=7
#################################
# loglevel-show Include log level indicator in log output
#
#loglevel-show=yes
#################################
# webserver Start a webserver for monitoring (api=yes also enables the HTTP listener)
#
#webserver=yes
#################################
# webserver-address IP Address of webserver/API to listen on
#
#webserver-address=0.0.0.0
#################################
# webserver-port Port of webserver/API to listen on
#
#webserver-port=8081
#################################
# webserver-allow-from Webserver/API access is only allowed from these subnets
#
#webserver-allow-from=0.0.0.0/0
#################################
# api Enable/disable the REST API (including HTTP listener)
#
#api=yes
#################################
# api-key Static pre-shared authentication key for access to the REST API
#
#api-key=mykey
新增配置 /etc/powerdns/pdns.d/pdns.backend.geoip.conf
launch=geoip
geoip-database-files=/var/lib/GeoIP/GeoLite2-City.mmdb
geoip-zones-file=/etc/powerdns/geoip.yaml
edns-subnet-processing=yes
新增配置 /etc/powerdns/geoip.yaml
domains:
- domain: example.com
ttl: 30
records:
# Default NS
ns1.example.com:
- a:
content: 10.0.0.1
ttl: 86400
ns2.example.com:
- a:
content: 10.0.0.2
ttl: 86400
example.com:
- soa: ns1.example.com hostmaster.example.com 2014090125 7200 3600 1209600 3600
- ns: ns1.example.com
- ns: ns2.example.com
- mx: 5 mx.example.com
- a: 192.0.2.1
default.geo.example.com:
- a: 192.0.2.2
- txt: hello world
- aaaa: 2001:DB8::12:34DE:3
ip.info.example.com:
- txt: "IP%af: %ip, Continent: %cn, Country: %co, ASn: %as, Region: %re, Organisation: %na, City: %ci"
beijing-server.example.com: &beijing
- a:
content: 192.1.1.1
weight: 90
- a:
content: 192.2.2.2
weight: 10
shenzhen-server.example.com: &shenzhen
- a: 192.3.3.3
guangzhou-server.example.com: &guangzhou
- a: 192.4.4.4
shanghai-server.example.com: &shanghai
- a: 192.5.5.5
unknown.unknown.geo.example.com: *beijing
unknown.gd.geo.example.com: *shenzhen
guangzhou.gd.geo.example.com: *guangzhou
shanghai.sh.geo.example.com: *shanghai
services:
www.example.com:
default: [ '%ci.%re.geo.example.com', 'unknown.%re.geo.example.com', 'unknown.unknown.geo.example.com']
101.227.102.0/24: 'beijing-server.example.com'
116.31.96.0/24:
- 'guangzhou-server.example.com'
- 'shenzhen-server.example.com'
mapping_lookup_formats: ['%ci-%re', '%re']
custom_mapping:
fr: eu-central
us-ca: us-south
使用占位符另一个作用是可以避免使用到 Packet Cache 和 Query Cache 产生缓存记录。
重启服务
systemctl restart pdns
或者
pdns_control reload
验证 ECS 功能
# 查看客户端IP GeoIP2 信息
dig +subnet=202.120.224.58 +short ip.info.example.com @127.0.0.1 txt
# 自定义区域-广州IP
dig +subnet=116.31.96.1 www.example.com @127.0.0.1
# 自定义区域-上海IP
dig +subnet=101.227.102.1 www.example.com @127.0.0.1
# 动态匹配客户端-上海IP
dig +subnet=202.120.224.58 www.example.com @127.0.0.1
# 动态匹配客户端-匹配不到位置的IP
dig +subnet=103.116.76.58 www.example.com @127.0.0.1
pdns.conf 常用参数
缓存相关参数:
- cache-ttl:单位秒,默认 20,Packet Cache。
- query-cache-ttl:单位秒,默认 20,Query Cache。
- negquery-cache-ttl:单位秒,默认 20,与上面相反,存储无结果的 Query Cache。
- zone-cache-refresh-interval:单位秒,默认 300,存储所有已知的 zones。
日志相关参数:
- log-dns-details:字面意思,使日志记录的 DNS 更详细,而不只是结果。
- log-dns-queries:记录所有传入的 DNS 查询请求。
- log-timestamp:字面意思,每条日志前面都会添加时间戳。
- logging-facility:用于指定日志消息所属的类别或“设施”,通常配合 syslog 或 rsyslog(增强版)使用。例如:user 表示用户级程序;syslog 是系统日志;local0 至 local7 是用户自定义日志类别。
- loglevel:对应 syslog 级别,数字越大日志输出越详细。(e.g. 0 = emergency, 1 = alert, 2 = critical, 3 = error, 4 = warning, 5 = notice, 6 = info, 7 = debug)
- loglevel-show:需要 4.9.x 以上版本。启用后会格式化日志输出。
开启 REST API 服务
通常搭配某些管理程序,例如:PowerDNS-Admin。
配置文件 /etc/powerdns/pdns.conf
#################################
# webserver Start a webserver for monitoring (api=yes also enables the HTTP listener)
#
webserver=yes
#################################
# webserver-address IP Address of webserver/API to listen on
#
webserver-address=0.0.0.0
#################################
# webserver-port Port of webserver/API to listen on
#
webserver-port=8081
#################################
# webserver-allow-from Webserver/API access is only allowed from these subnets
#
webserver-allow-from=0.0.0.0/0
#################################
# api Enable/disable the REST API (including HTTP listener)
#
api=yes
#################################
# api-key Static pre-shared authentication key for access to the REST API
#
api-key=mykey
重启服务后,查看 8081 端口是否监听
root@pdns:~# netstat -tunlp | grep 8081
tcp 0 0 0.0.0.0:8081 0.0.0.0:* LISTEN 2392446/pdns_server
验证请求是否成功响应
curl -v -H 'X-API-Key: mykey' http://127.0.0.1:8081/api/v1/servers/localhost | jq .
查看日志排查错误
配置 local0 作为 pdns 日志类别,添加配置到 /etc/powerdns/pdns.conf
#################################
# logging-facility Log under a specific facility
#
logging-facility=0
保存日志到自定义文件
cat << EOF >/etc/rsyslog.d/51-pdns.conf
local0.* /var/log/pdns.log
EOF
重启服务
systemctl restart rsyslog && systemctl restart pdns
查看 pdns 服务启动日志
journalctl -u pdns
实时跟踪 pdns_server 进程响应信息
strace -fp $(pgrep pdns_server)
评论区