PowerDNSは、高性能で安定したDNSサーバソフトウェアです。オープンソースのプロジェクトとして開発されており広く普及しています。
特徴
- モジュール式アーキテクチャ: PowerDNSは柔軟なモジュール式アーキテクチャを採用しており、拡張性が高いです。バックエンドシステムとして、MySQL, PostgreSQL, SQLite, LDAPなどを利用することができます。
- 高いパフォーマンス: PowerDNSは、大規模なDNS設定も効率的かつ高速に管理することができます。
- API対応: RESTful APIを介して設定や管理が可能であり、自動化やリモートからの操作が容易です。
- セキュリティ: PowerDNSは、セキュリティに力を入れており、DNSSEC (Domain Name System Security Extensions) やDNS-over-TLS/HTTPSなどのセキュリティ機能をサポートしています。
- IPv6対応: PowerDNSはIPv6をフルサポートします。
PowerDNS Authoritative Serverをインストールする
必要なリポジトリを追加する
まず、EPEL (Extra Packages for Enterprise Linux) リポジトリとPowerDNS公式リポジトリを追加します。
sudo yum install epel-release -y
sudo curl -o /etc/yum.repos.d/powerdns-auth-48.repo https://repo.powerdns.com/repo-files/centos-auth-48.repo
PowerDNS Authoritative Serverとバックエンドデータベースをインストール
この例では、MySQLバックエンドを使用しています。
sudo yum install pdns pdns-backend-mysql -y
MariaDB(MySQL) をインストールおよび設定する
MariaDB(MySQL)は導入済みという前提です。
MariaDB(MySQL) サーバーをインストールし、PowerDNSのためのデータベースとユーザーを作成します。
データベースとユーザーを作成し、権限を付与します。
mysql -u root -p
CREATE DATABASE powerdns;
GRANT ALL ON powerdns.* TO 'powerdns'@'localhost' IDENTIFIED BY 'ここにパスワード';
FLUSH PRIVILEGES;
EXIT;
スキーマをインポートします。
mysql -u powerdns -p powerdns < /usr/share/doc/pdns-backend-mysql/schema.mysql.sql
PowerDNSを設定する
pdnsから設定ファイルを読み込めるようにします。
chown -R pdns.pdns /etc/pdns
/etc/pdns/pdns.conf
ファイルを編集して、MySQLバックエンドを設定します。
sudo vi /etc/pdns/pdns.conf
最下行に以下を追加します。
launch=gmysql
gmysql-host=localhost
gmysql-user=powerdns
gmysql-password=ここにパスワード
gmysql-dbname=powerdns
設定後、PowerDNSサービスを有効化して起動します。
sudo systemctl enable pdns
sudo systemctl start pdns
ファイアウォールの設定
DNSサーバーに接続できるように、ファイアウォールの設定を変更します。
sudo firewall-cmd --permanent --add-service=dns
sudo firewall-cmd --reload
これで、CentOSでPowerDNSを使用したセキュアなDNSサーバーが構築されました。必要に応じて、レコードをデータベースに追加し、DNSクライアントで名前解決をテストできます。
Poweradmin の導入
Poweradminは、PowerDNSサーバをWebベースで管理するためのPHPアプリケーションです。次の手順に従って、Poweradminを導入します。
前提条件
- PowerDNSとそのバックエンドデータベース(MySQL, PostgreSQLなど)が設定済みであること
- Webサーバ(ApacheやNginx等)がインストールされていること
- PHPがインストールされており動作していること
Poweradminのダウンロード
公式GitHubリポジトリから最新版のPoweradminをダウンロードして解凍します。
wget https://github.com/poweradmin/poweradmin/archive/refs/tags/v3.5.1.tar.gz
tar -zxvf v3.5.1.tar.gz
解凍したファイルをWebサーバのドキュメントルートにコピー
例として、Apacheのドキュメントルート/var/www/html
/poweradminにコピーします。
mv poweradmin-3.5.1 /var/www/html/poweradmin
データベースの設定
PoweradminとPowerDNSのデータベースを分ける必要はありません。
PowerDNSで設定したデータベースをそのまま利用します。
Poweradminのインストールウィザードにアクセス
Webブラウザで、Poweradminのインストールウィザードにアクセスします。
https://your_domain/poweradmin/install/
以下のような画面が表示されましたら、インストールウィザードに表示される手順に従い、以下の設定を行います。
データベース情報はPowerDNSに設定したものを入力します。
Poweradmin管理者のパスワードは、Poweradminの初期アカウント admin のパスワードです。
ホストマスター、ネームサーバーは必須です。
設定しないと、SOAレコードが正しく登録されずレコードが参照できなくなりますので、正しく設定してください。
以上で、Poweradminの導入が完了しました。WebブラウザからPowerDNSサーバを管理できるようになります。
日本語でエラーlocale表示がでる不具合を直す
Error: Failed to set locale. Selected locale may be unsupported on this system. Please contact your administrator.
このエラーが日本語にすると、画面上部に表示されます。
localeを $iface_lang . ‘.UTF-8’ によって生成してるプログラムを変更します。
vi inc/i18n.inc.php
#$locale = setlocale(LC_ALL, $iface_lang, $iface_lang . '.UTF-8');
$locale = setlocale(LC_ALL, $iface_lang, $iface_lang . '.utf8');
locale -a で表示される方にあわせました。
locale -a
C
C.utf8
POSIX
ja_JP.eucjp
ja_JP.utf8
localectl list-locales
C.UTF-8
ja_JP.UTF-8
トラブルシューティング
PowerDNSのサービスは正常に動作しているのに、digコマンド等で確認すると応答が返ってこない場合は、登録済みのレコードを確認します。当該ドメインに1つでも異常のあるレコードがあると、そのドメインの全てのレコードが使用できません。特に、Poweradminを使用する場合は、SOAレコードに必要情報が不足した状態でも登録されてしまうため、まずSOAレコードを確認されることをお勧めします。
pdnsutil check-zone で確認すると参考になる情報が得られると思います。
pdnsutil check-zone example.com
[Error] SOA lookup failed for zone 'example.com': Out of range exception parsing ' 2023060901 28800 7200 604800 86400'
[Info] SOA autocomplete is deprecated, missing field(s) in SOA content: example.com IN SOA ' 2023060901 28800 7200 604800 86400'
[Warning] Parsed and original record content are not equal: example.com IN SOA ' 2023060901 28800 7200 604800 86400 0 0' (Content parsed as '2023060901. 28800. 7200 604800 86400 0 0')
[Error] No NS record at zone apex in zone 'example.com'
Checked 2 records of 'example.com', 2 errors, 1 warnings.
dig コマンド
dig
(Domain Information Groper)はDNS(ドメインネームシステム)の問い合わせと表示を行うコマンドラインツールです。以下に、一般的な使い方とオプションを示します。
基本的な使用方法
ドメイン名のIPアドレスを調べる場合、次のように実行します。
dig example.com
特定のレコードタイプの問い合わせ
特定のレコードタイプ(A, AAAA, MX, NS, CNAME, SOA, TXT など)を指定して問い合わせます。
dig MX example.com
短い結果の表示
結果を短くする場合(回答セクションのみ表示)、+short
オプションを使用します。
dig example.com +short
特定のDNSサーバーからの問い合わせ
特定のDNSサーバーに対して問い合わせる場合、サーバーのIPアドレスまたはホスト名を指定します。
dig @8.8.8.8 dns.google
; <<>> DiG 9.16.23-RH <<>> @8.8.8.8 dns.google
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 59341
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;dns.google. IN A
;; ANSWER SECTION:
dns.google. 625 IN A 8.8.8.8
dns.google. 625 IN A 8.8.4.4
;; Query time: 3 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Sat Jun 10 12:12:33 JST 2023
;; MSG SIZE rcvd: 71
逆引きの問い合わせ
IPアドレスからドメイン名を取得するために、-x
オプションを使用します。
dig -x 8.8.8.8
; <<>> DiG 9.16.23-RH <<>> -x 8.8.8.8
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 24363
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;8.8.8.8.in-addr.arpa. IN PTR
;; ANSWER SECTION:
8.8.8.8.in-addr.arpa. 86400 IN PTR dns.google.
;; Query time: 358 msec
;; SERVER: 157.7.180.133#53(157.7.180.133)
;; WHEN: Sat Jun 10 12:12:59 JST 2023
;; MSG SIZE rcvd: 73
PowerDNS を Native運用する
PowerDNSをMariaDBのレプリケーション機能とともにNativeで運用するためには、以下のようなステップが必要です。これらのステップを通じて、一つのMariaDBサーバ(マスター)上の変更が他のMariaDBサーバ(スレーブ)に同期される設定を行います。
Master側の設定
レプリケーションを開始する前に、すでにレコードが登録されている場合は、予めSlave側にインポートしておきましょう。
sudo vi /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
log-error=/var/log/mariadb/mariadb.log
pid-file=/run/mariadb/mariadb.pid
# 以下を追加する binlog_do_dbにレプリケーションしたいデータベースを指定する
server-id = 1
log_bin = /var/log/mariadb/mariadb-bin.log
binlog_do_db = powerdns
外部からの接続を許可するために
bind-address=0.0.0.0をコメントアウトします。
[galera]
# Mandatory settings
#wsrep_on=ON
#wsrep_provider=
#wsrep_cluster_address=
#binlog_format=row
#default_storage_engine=InnoDB
#innodb_autoinc_lock_mode=2
#
# Allow server to accept connections on all interfaces.
#
bind-address=0.0.0.0
#
# Optional setting
#wsrep_slave_threads=1
#innodb_flush_log_at_trx_commit=0
# this is only for embedded server
MariaDB サーバを再起動します。
sudo systemctl restart mariadb.service
レプリケーション用ユーザーを作成し、そのユーザーがスレーブから接続できるように許可する。
mysql -u root -p
passwordは任意のものに変更してください。 replication_userは任意のものに問題ありませんが、レプリケーション用と分かりやすい名前にしておくと良いでしょう。
GRANT REPLICATION SLAVE ON *.* TO 'replication_user'@'%' IDENTIFIED BY 'password';
FLUSH PRIVILEGES;
MariaDB [(none)]> SHOW MASTER STATUS;
+--------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+--------------------+----------+--------------+------------------+
| mariadb-bin.000001 | 330 | powerdns | |
+--------------------+----------+--------------+------------------+
1 row in set (0.000 sec)
Position のところにある、数字を覚えておきます。 ここでは「330」です。
firewalld の設定
slaveサーバーから 3306/tcp を許可する必要があります。
firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="***.***.***.*" port protocol="tcp" port="3306" accept'
firewall-cmd --reload
firewall-cmd --list-all
Slave側の設定
レプリケーション開始前に、master側にレコードがある場合は、予めインポートしておいてください。
sudo vi /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
log-error=/var/log/mariadb/mariadb.log
pid-file=/run/mariadb/mariadb.pid
# 以下を追加
server-id = 2
relay_log = /var/log/mariadb/mariadb-relay-bin.log
log_bin = /var/log/mariadb/mariadb-bin.log
binlog_do_db = powerdns
MariaDB サーバを再起動します。
sudo systemctl restart mariadb.service
mysql -u root -p
CHANGE MASTER TO MASTER_HOST='master_host_ip',
MASTER_USER='replication_user',
MASTER_PASSWORD='password',
MASTER_LOG_FILE='mariadb-bin.000001',
MASTER_LOG_POS= 330;
START SLAVE;
Slave側のMariaDBの再起動は不要です。
MariaDB [(none)]> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: ***.***.***.**
Master_User: replication_user
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mariadb-bin.000002
Read_Master_Log_Pos: 344
Relay_Log_File: mariadb-relay-bin.000002
Relay_Log_Pos: 557
Relay_Master_Log_File: mariadb-bin.000002
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 344
Relay_Log_Space: 868
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 1
Master_SSL_Crl:
Master_SSL_Crlpath:
Using_Gtid: No
Gtid_IO_Pos:
Replicate_Do_Domain_Ids:
Replicate_Ignore_Domain_Ids:
Parallel_Mode: optimistic
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
Slave_DDL_Groups: 0
Slave_Non_Transactional_Groups: 0
Slave_Transactional_Groups: 0
1 row in set (0.000 sec)
ERROR: No query specified
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
このような表示になれば動作しているかと思います。