ぶっちゃけ「ALIAS レコードが使いたい」というだけの理由で、PowerDNS に乗り換えた。
だが本気で乗り換えてみれば、PDNS Manager でレコード編集は楽だし、バックエンドを MariaDB にしてレプリケーションさせればゾーンの増減時にスレーブでの作業が不要になってさらに楽。
ただし構築は NSD と比べて手間がかかる。
マスターが master.example.com (192.0.2.1)、スレーブが slave.example.com (198.51.100.1) という構成を想定して書いていく。
DNS 的なゾーン転送 (AXFR) をするわけではないのだが、一応。
マスターはメモリ 2GB で nginx 等も動作しており、スレーブはメモリ 512MB で DNS のみを担当という想定。想定というか実際そうなのだけれども。
ALIAS レコードを使うので、127.0.0.1:53 に PowerDNS Recursor を動かす。
手順は Debian でも Ubuntu でもほぼ同じ。実際に私のスレーブのうち1台は Ubuntu である。
(ただし /etc/mysql/my.cnf だけなぜか Ubuntu だとないので、Debian からコピーした)
MariaDB、PowerDNS の導入
マスター、スレーブで共通の作業。
MariaDB は Debian 収録物ではなく MariaDB Repositories で導入する。
ただ add-apt-repository は好みじゃないので手順を少し変更。
sudo apt install dirmngr
sudo apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 0xF1656F24C74CD1D8
echo 'deb http://ftp.yz.yamagata-u.ac.jp/pub/dbms/mariadb/repo/10.3/debian stretch main' | sudo tee /etc/apt/sources.list.d/mariadb.list
sudo apt update
sudo apt install mariadb-server
PowerDNS も Debian 収録物ではなく PowerDNS repositories で導入する。
wget https://repo.powerdns.com/FD380FBB-pub.asc -O - | sudo apt-key add -
echo 'deb http://repo.powerdns.com/debian stretch-rec-41 main' | sudo tee /etc/apt/sources.list.d/pdns.list
echo 'deb http://repo.powerdns.com/debian stretch-auth-41 main' | sudo tee -a /etc/apt/sources.list.d/pdns.list
sudo apt update
sudo apt install pdns-recursor pdns-server pdns-backend-mysql
pdns-server が起動失敗するが、この時点ではそれで問題ない。
標準では pdns-server が *:53 を listen するのだが、127.0.0.1:53 を先に pdns-recursor が listen しているため、pdns-server が listen できないのだ。
MariaDB のインスタンスを分ける
マスターでは DNS 以外の仕事も担当しており、MariaDB は PowerDNS のみを収容しているわけではない。
しかし MariaDB の REPLICATION SLAVE 権限は特定のデータベースのみを対象とする権限ではなくグローバル権限なので、スレーブがマスターのデータベースすべてをレプリケーションする権限を持ってしまう (権限を持った上で、スレーブ側の設定でレプリケーションするデータベースを絞る、という形になる)。
これはセキュリティ上好ましくないので、PowerDNS 専用の MariaDB インスタンスを別に立ち上げる。
MariaDB を複数インスタンス起動する手段として、ちょっと古い記事だと mysqld_multi を使う説明が多いのだが、mariadb.service の代わりに mariadb@.service を使うという手段がある。
systemctl start mariadb@HOGE すると、mysqld –defaults-file=/etc/mysql/conf.d/myHOGE.cnf が実行される仕組み。この場合 /etc/mysql/my.cnf は読み込まれない。
なので /etc/mysql/my.cnf から末尾の !include-dir を除去したものを /etc/mysql/conf.d/mymariadb.cnf に置く。!include-dir /etc/mysql/conf.d なので除去しないと無限ループ。
!include の方は残してもいいが、PowerDNS 専用インスタンスはすべて mypdns.cnf に記述するので、!include も除去して mymariadb.cnf だけで済ませる方が統一感があるように思われる。
PowerDNS 専用インスタンスは次の設定とする。
- ソケット /var/run/mysql/mysqld_pdns.sock
- PID /var/run/mysql/mysqld_pdns.pid
- ポート 3307
- データディレクトリ /var/lib/mysql_pdns
- バイナリログ /var/log/mysql/mariadb_pdns_bin
- server-id 1
sudo systemctl stop mariadb
sudo systemctl disable mariadb
sed -e '/^!include/d' /etc/mysql/my.cnf | sudo tee /etc/mysql/conf.d/mymariadb.cnf
sed -e '/^!include/d' -e 's/\/var\/lib\/mysql/\/var\/lib\/mysql_pdns/g' -e 's/mysqld.\(sock\|pid\)/mysqld_pdns.\1/g' -e 's/3306/3307/g' 's/#\(server-id\)/\1/' -e 's/mariadb-bin/mariadb_pdns_bin/g' /etc/mysql/my.cnf | sudo tee /etc/mysql/conf.d/mypdns.cnf
sudo mysql_install_db --datadir=/var/lib/mysql_pdns
sudo systemctl enable mariadb@mariadb mariadb@pdns
sudo systemctl start mariadb@mariadb mariadb@pdns
PDNS Manager を使うので、空のデータベース pdns を作っておく。
同時にユーザー pdns@localhost、レプリケーション用ユーザー pdnsrepl@localhost も作る。
root のパスワードが空なので、これもパスワードを設定しておく。
mariadb を導入した時点で root のパスワードをつけたじゃないかって? それは mariadb@mariadb における root のパスワードで、mariadb@pdns における root のパスワードではない。
PowerDNS 慣れしている人はここでテーブルを作りそうになると思うが、PDNS Manager がテーブルを作るので、空のまま。
sudo mysql -P 3307 -h 127.0.0.1
CREATE DATABASE pdns;
GRANT USAGE ON *.* TO pdns@localhost IDENTIFIED BY 'パスワード';
GRANT ALL ON pdns.* TO pdns@localhost;
GRANT REPLICATION SLAVE ON *.* TO pdnsrepl@localhost IDENTIFIED BY 'パスワード';
UPDATE mysql.user SET password=PASSWORD('パスワード') WHERE user='root';
FLUSH PRIVILEGES;
\q
スレーブでもデータベース pdns、ユーザー pdns@localhost を作っておく。
sudo mysql -p
CREATE DATABASE pdns;
GRANT USAGE ON *.* TO pdns@localhost IDENTIFIED BY 'パスワード';
GRANT ALL ON pdns.* TO pdns@localhost;
\q
PDNS Manager の導入
マスターでの作業。
PDNS Manager を入れる。
公式サイトの説明が今時珍しく Apache での説明しか書かれていないので、nginx での設定を書いておく (PHP は php-fpm を使っている)。
server {
server_name pdns.example.com;
root /var/www/html/backend/public;
index index.html index.php;
location / {
root /var/www/html/frontend;
try_files $uri $uri/ /index.html;
}
location /api {
try_files $uri $uri/ /index.php;
}
location ~ [^/]\.php(/|$) {
if ($request_uri ~* "/api(.*)") {
set $req $1;
}
fastcgi_pass unix:/run/php/php7.3-fpm.sock;
fastcgi_split_path_info ^(/api)(/.*)$;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
fastcgi_param REQUEST_URI $req;
}
}
https://pdns.example.com/setup をブラウザーで開き、初期設定を行う。
基本的に Getting Started の通りだし、ぶっちゃけ画面見ればどこに何を入力すべきか一目瞭然だが、注意点が一つ。
Database の Host は localhost ではなく 127.0.0.1 とする。
127.0.0.1 を指定しないと mariadb@pdns ではなく標準の方 (mariadb@mariadb) につながってしまうため。
コマンドラインで mysql -P 3307 -h 127.0.0.1 としていたのも同じ理由による。
ドメインの追加は、Add domain | MASTER | NATIVE | SLAVE とある中で、NATIVE で行う。
PowerDNS でゾーン転送 (AXFR) するのではなく、バックエンドである MariaDB を使って同期するためだ。
ssh port forwarding の設定
MariaDB は標準の設定ファイルでは localhost しか listen しないし、これを開放するのはセキュリティ上好ましくない。
なので、スレーブからマスターに ssh port forwarding で接続できるよう設定する。
レプリケーション用のシステムアカウントを作り、autossh で接続を維持する。
マスター、スレーブで共通の作業:
sudo useradd -r -s /usr/sbin/nologin -d /etc/powerdns/pdnsrepl pdnsrepl
sudo mkdir /etc/powerdns/pdnsrepl
sudo chown pdnsrepl:pdnsrepl /etc/powerdns/pdnsrepl
sudo chmod 700 /etc/powerdns/pdnsrepl
sudo -u pdnsrepl mkdir /etc/powerdns/pdnsrepl/.ssh
sudo -u pdnsrepl chmod 700 /etc/powerdns/pdnsrepl/.ssh
スレーブでの作業:
sudo -u pdnsrepl ssh-keygen -t ed25519
sudo apt install autossh
スレーブの /etc/powerdns/pdnsrepl/.ssh/id_ed25519.pub の内容を、マスターの /etc/powerdns/pdnsrepl/.ssh/authorized_keys に貼り付け。
もちろん authorized_keys は 600 にする。
スレーブで /etc/systemd/system/autossh-pdnsrepl.service を作成。
[Unit]
Description=AutoSSH port forwarding for PowerDNS DB replication
[Service]
ExecStart=/usr/bin/sudo -u pdnsrepl /usr/bin/autossh -f -M 0 -N -L 3307:127.0.0.1:3307 -o "ServerAliveInterval 45" -o "ServerAliveCountMax 2" pdnsrepl@master.example.com
ExecStop=/usr/bin/killall -KILL autossh
Type=forking
[Install]
WantedBy=multi-user.target
スレーブでの作業:
sudo -u pdnsrepl ssh pdnsrepl@master.example.com
sudo systemctl enable autossh-pdnsrepl
sudo systemctl start autossh-pdnsrepl
これで、スレーブで 127.0.0.1:3307 に接続するとマスターの 127.0.0.1:3307 につながるようになった。
レプリケーションの設定
マスターでの作業:
sudo mysql -P 3307 -h 127.0.0.1 -p
FLUSH TABLES WITH READ LOCK;
\q
sudo mysqldump -P 3307 -h 127.0.0.1 -p pdns --lock-all-tables > pdns.db
sudo mysql -P 3307 -h 127.0.0.1 -p
UNLOCK TABLES;
SHOW MASTER STATUS;
\q
SHOW MASTER STATUS; で表示されたファイル名とポジションをメモりつつ、できた pdns.db をスレーブにコピーする。
スレーブでの作業:
sudo mysql pdns -p < pdns.db
sudo systemctl stop mariadb
/etc/mysql/mariadb.conf.d/slave.cnf を作成。
マスターでは my.cnf をベースに編集したファイルを mariadb@.service で直接読み込ませていたが、スレーブでは MariaDB インスタンスを分けず mariadb.service で起動するため、最小限の追加で済ませる。
[mysqld]
server_id = 2
read_only
replicate_do_db = pdns
スレーブでの作業:
sudo systemctl start mariadb
sudo mysql -p
CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=3307, MASTER_USER='pdnsrepl', MASTER_PASSWORD='(マスターで pdnsrepl@localhost につけたパスワード)', MASTER_LOG_FILE='(マスターの SHOW MASTER STATUS; で表示されたファイル名)', MASTER_LOG_POS=(マスターの SHOW MASTER STATUS; で表示されたポジションの数字);
START SLAVE;
\q
PowerDNS の設定
/etc/powerdns/pdns.d/mysql.conf を作成。
マスター:
launch+=gmysql
gmysql-dbname=pdns
gmysql-user=pdns
gmysql-password=パスワード
gmysql-socket=/var/run/mysqld/mysqld_pdns.sock
スレーブ:
launch+=gmysql
gmysql-dbname=pdns
gmysql-user=pdns
gmysql-password=パスワード
gmysql-socket=/var/run/mysqld/mysqld.sock
/etc/powerdns/pdns.conf を編集。
変更点は以下の通り。
- expand-alias=yes
- local-address は外側 IP アドレス (本記事の想定ではマスター 192.0.2.1、スレーブ 198.51.100.1) に設定する。
- IPv6 がない場合、local-ipv6= にする。
- resolver=127.0.0.1
pdns-server を起動。
sudo systemctl start pdns
完了。