利用PowerDNS架设自己的解析服务器

之前白嫖的DNS服务器因为种种原因不能再继续利用了(虽然解析还在)
考虑到要用GeoIP+低于5分钟的缓存,又不想花钱买服务,那么就只有自建了

另外:PowerDNS不支持CNAMEX,对此有需求的人需要考虑别的解决方案(之前白嫖的DNS服务是支持的,CNAMEX可以在DNS层通过调整比例的方式,变相的来实现负载均衡,这在给一个地区部署多台CDN,或者利用多个CDN商家的服务时相当方便,可以从带宽、性能、流量价格的角度来直接调整比例)

GUI选择了PowerDNS-Admin,主要是因为好看,没别的理由

使用的环境和所需的各种:
Debian 10
MariaDB
GeoIP
PowerDNS
pdns-backend-mysql
pdns-backend-geoip
PowerDNS-Admin GUI
Nginx
Git

参考资料:官方文档 官方文档-Backend支持列表 久しぶりにPowerDNSをさわる PowerDNS-Admin GitHub PowerDNS-Admin – Roll Your Own Network

1、安装pdns+配置数据库

apt-get install mariadb-server pdns-server pdns-backend-geoip pdns-backend-mysql

已经安装过mariadb的话从里面删掉mariadb即可
然后做一下数据库的安全设置、建表和创建一个用户给pdns用

mysql_secure_installation

Change the root password? [Y/n] y
Remove anonymous users? [Y/n] y
Disallow root login remotely? [Y/n] y
Remove test database and access to it? [Y/n] y
Reload privilege tables now? [Y/n] y

mysql -u root -p

create database pdns character set utf8 collate utf8_bin;
grant all privileges on pdns.* to pdns@localhost identified by 'YOURPASSWORD';
FLUSH PRIVILEGES;
quit;

安全设置上,大致就是修改root账户密码,删除匿名用户,禁用root远程登录,删除测试库,重新加载表等,详细的解释会在每条确认的上面有输出。

测试一下登陆,顺便把表建立一下。
PS:务必去从官方文档复制,版本更新后有可能所需要的表也会更新

mysql -u pdns -p

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(6) NOT NULL,
  notified_serial       INT DEFAULT NULL,
  account               VARCHAR(40) CHARACTER SET 'utf8' DEFAULT NULL,
  PRIMARY KEY (id)
) Engine=InnoDB CHARACTER SET 'latin1';

CREATE UNIQUE INDEX name_index ON domains(name);

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,
  change_date           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,
  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;

然后改配置文件,把数据库相关的内容写进去

vim /etc/powerdns/pdns.conf

launch=gmysql
gmysql-host=127.0.0.1
gmysql-user=pdns
gmysql-dbname=pdns
gmysql-password=YOURPASSWORD
gmysql-dnssec=yes

保存退出后,执行一次pdns来初始化一下,在这之前需要先把pdns关闭(装好后会默认以服务的形式启动了)

systemctl stop pdns.service

pdns_server

只要没有报错的话Ctrl+C退出即可,然后再启动服务即可

2、安装并配置PowerDNS-Admin

PowerDNS-Admin目前为止只支持Python 2,根据公开的资料来看有支持Python 3的计划。
以及PowerDNS-Admin使用API和PDNS通讯,所以两边都需要配置一番。
另外,他还需要单独用数据库,所以也需要给他配置一个账号和表。

先把PowerDNS-Admin拉下来

git clone https://github.com/ngoduykhanh/PowerDNS-Admin.git /opt/web/powerdns-admin

准备一个api来给pdns-admin用

vim /etc/powerdns/pdns.conf

api=yes
api=key=YOURAPIKEY
webserver=yes

systemctl restart pdns.service

curl -v -H 'X-API-Key: YOURAPIKEY' http://127.0.0.1:8081/api/v1/servers/localhost | jq .

准备一个数据库的用户
在参考其他教程的时候发现有一部分有提及需要自己建表,然而参照和测试后确认目前的版本只需要写好数据库账号密码到配置文件里,之后执行一下即可自动初始化,所以这里只需要配置用户和库。

mysql -u root -p

CREATE DATABASE pdnsadmin character set utf8 collate utf8_bin;
GRANT ALL PRIVILEGES ON pdnsadmin.* TO 'pdnsadmin'@'localhost' IDENTIFIED BY 'YOURPASSWORD';
FLUSH PRIVILEGES;
quit;

然后准备一下依赖
从debian9开始,libmysqlclient-dev变成了default-libmysqlclient-dev,这里也跟着改变

apt-get install python3-dev default-libmysqlclient-dev libsasl2-dev libldap2-dev libssl-dev libxml2-dev libxslt1-dev libxmlsec1-dev libffi-dev pkg-config apt-transport-https virtualenv build-essential

curl -sL https://deb.nodesource.com/setup_10.x | bash -
apt-get install nodejs

curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
apt-get update
apt-get install yarn

需要设置一下config,复制一下模版然后修改内容

cd /opt/web/powerdns-admin

cp config_template.py config.py

vim config.py

# BASIC APP CONFIG
SECRET_KEY = 'YOURSECRETKEY'

# DATABASE CONFIG
SQLA_DB_USER = 'pdnsadmin'
SQLA_DB_PASSWORD = 'YOURPASSWD'
SQLA_DB_HOST = '127.0.0.1'
SQLA_DB_PORT = 3306
SQLA_DB_NAME = 'pdnsadmin'

# POWERDNS CONFIG
PDNS_STATS_URL = 'http://127.0.0.1:8081/'
PDNS_API_KEY = 'YOURAPIKEY'
PDNS_VERSION = 'YOURPDNSVER'

保存退出,然后继续

virtualenv -p python3 flask
source ./flask/bin/activate

这时候最左侧会多出来一个“(flask)”,继续操作

pip install -r requirements.txt
pip install python-dotenv

flask db upgrade
yarn install --pure-lockfile
flask assets build

./run.py

如果一切正常的话那么run之后就会自动启动pdns-admin,可以通过http://127.0.0.1:8081/来访问。
进入后需要手动创建一个账户,第一个账户默认为管理员,之后跟随者GUI的指示进行操作即可。

3、配置systemctl和nginx

官方文档在这啦,懒的人复制粘贴就可以了……(路径要和你实际放着的位置统一)
如果你懒得点开的话就复制下面的吧(我帮你复制到这里了)

vim /etc/systemd/system/powerdns-admin.service


[Unit]
Description=PowerDNS-Admin
After=network.target

[Service]
User=root
Group=root
WorkingDirectory=/opt/web/powerdns-admin
ExecStart=/opt/web/powerdns-admin/flask/bin/gunicorn --workers 2 --bind unix:/opt/web/powerdns-admin/powerdns-admin.sock app:app

[Install]
WantedBy=multi-user.target


systemctl daemon-reload
systemctl enable powerdns-admin
systemctl start powerdns-admin

nginx的官方文档部分(只复制了使用SSL证书的参考)
这里使用了sock,路径如果有变动的话要改的地方比较多,要注意

server {
        listen                  80 default_server;
        server_name             "";
        return 301 https://$http_host$request_uri;
}

server {
        listen                  443 ssl http2 default_server;
        server_name             _;
        index                   index.html index.htm;
        error_log               /var/log/nginx/error_powerdnsadmin.log error;
        access_log              off;

        ssl_certificate                 path_to_your_fullchain_or_cert;
        ssl_certificate_key             path_to_your_key;
        ssl_dhparam                     path_to_your_dhparam.pem;
        ssl_prefer_server_ciphers       on;
        ssl_ciphers                     'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
        ssl_session_cache               shared:SSL:10m;

        client_max_body_size            10m;
        client_body_buffer_size         128k;
        proxy_redirect                  off;
        proxy_connect_timeout           90;
        proxy_send_timeout              90;
        proxy_read_timeout              90;
        proxy_buffers                   32 4k;
        proxy_buffer_size               8k;
        proxy_set_header                Host $http_host;
        proxy_set_header                X-Scheme $scheme;
        proxy_set_header                X-Real-IP $remote_addr;
        proxy_set_header                X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_headers_hash_bucket_size  64;

        location ~ ^/static/  {
                include         mime.types;
                root            /opt/web/powerdns-admin/app;
                location        ~* \.(jpg|jpeg|png|gif)$ { expires 365d; }
                location        ~* ^.+.(css|js)$ { expires 7d; }
        }

        location ~ ^/upload/  {
                include         mime.types;
                root            /opt/web/powerdns-admin;
                location        ~* \.(jpg|jpeg|png|gif)$ { expires 365d; }
                location        ~* ^.+.(css|js)$ { expires 7d; }
        }

        location / {
                proxy_pass              http://unix:/opt/web/powerdns-admin/powerdns-admin.sock;
                proxy_read_timeout      120;
                proxy_connect_timeout   120;
                proxy_redirect          http:// $scheme://;
        }
}

4、安装并配置GeoIP(未写完,先挖个坑)

访问GeoIP2并下载免费版数据库

wget https://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.tar.gz

tar -xzvf GeoLite2-Country.tar.gz

mkdir -p /usr/share/GeoIP

mv GeoLite2-Country.mmdb /usr/share/GeoIP/

然后写一下配置文件

vim /etc/powerdns/pdns.d/geoip.conf

launch=geoip
geoip-database-files=/usr/share/GeoIP/GeoLite2-Country.mmdb
geoip-database-cache=memory
geoip-zones-file=/share/zone.yaml