2026年6月9日
2026年6月9日
BIND から MaraDNS へ移行する手順|named.conf の棚卸し・fetchzone で csv2 に変換・並行稼働で切り替える
BIND から MaraDNS への移行は、「named.conf の棚卸しで MaraDNS に持っていけない機能を洗い出す → BIND からゾーン転送でゾーンを取り出して csv2 形式に変換する → MaraDNS を別のアドレスで動かして答えを比べる → 切り替える」の順に進めると、名前解決を止めずに済みます。変換には MaraDNS 付属の fetchzone を使うと、BIND 独自の $INCLUDE や $GENERATE を展開した結果をそのまま csv2 で受け取れるため、手で書き直すより誤りが入りにくくなります。この記事では、移行が向く構成の見極めから、変換、比較、切り替え、移行後の運用の変化までを説明します。
内容は BIND 9 系と MaraDNS 3.5 系を前提にしています(2026年10月現在)。コマンドのオプションや設定項目の名前は版によって異なることがあるため、手元の man と照らし合わせてください。作業前には named.conf とゾーンファイル一式のバックアップを取り、検証用のサーバーで一通り試してから本番に進みます。
移行が向く構成・向かない構成
MaraDNS は設定が少なく、小規模な権威サーバーを手軽に動かせるのが利点です。一方で、BIND が持つ機能の多くを持っていません。次の機能を使っている場合は、MaraDNS への移行は見送るか、代わりの手段を先に用意します。
- DNSSEC:MaraDNS は DNSSEC の署名に対応していません。署名済みのゾーンを運用しているなら、移行先は NSD や Knot DNS などを検討します。
- view(問い合わせ元による出し分け):MaraDNS には view に当たる機能がありません。社内向けと社外向けを分けているなら、サーバーを分ける構成を考えます。
- 動的更新(DDNS):
allow-updateやupdate-policyで外部から更新している場合(DHCP 連携や ACME の DNS 認証など)、MaraDNS では受け付けられません。 - TSIG によるゾーン転送の認証:MaraDNS のゾーン転送は IP アドレスでの制限が中心です。
- キャッシュサーバーとしての利用:BIND の
recursion yes;で社内向けの再帰問い合わせも受けているなら、その役割は MaraDNS 付属の Deadwood に分けて、別のアドレスで動かします。
逆に、少数のゾーンを静的に配っているだけの権威サーバーであれば、移行の手間は小さく済みます。
手順1:named.conf を棚卸しする
まず、BIND が実際に読んでいる設定を確認します。named-checkconf -p は、include を展開したうえで設定全体を書き出します。
sudo named-checkconf -p > ~/bind-config-dump.txt
grep -nE '^zone|type |file |allow-update|update-policy|dnssec-policy|inline-signing|view |recursion' ~/bind-config-dump.txt
確認するのは次の点です。
- ゾーンの一覧と種類:
type primary(古い書き方ではmaster)のゾーンが移行の対象です。type secondary(slave)のゾーンは、MaraDNS ではそのままセカンダリとして受けられないため、扱いを別に決めます。 - 上の「向かない機能」を使っていないか:
dnssec-policy・inline-signing・allow-update・viewが出てきたら、そのゾーンは個別に検討します。 - 再帰問い合わせ:
recursionの設定と、allow-recursionで許可している範囲を控えます。Deadwood に移す場合に使います。 - ゾーン転送の相手:
allow-transferとalso-notifyに書かれたセカンダリを控えます。移行後も MaraDNS の zoneserver から転送する必要があります。
移行中はレコードの変更をできるだけ止めておきます。変更が入ると、比較と切り戻しが難しくなります。
手順2:fetchzone でゾーンを csv2 に変換する
fetchzone は、指定したサーバーからゾーン転送(AXFR)でゾーンを受け取り、csv2 形式で標準出力に書き出すツールです。MaraDNS のビルド時に作られます。make install でインストールされない版では、ビルドしたソースツリーの tools 配下にあるので、そこから実行します。
BIND 側で、作業するホストからの転送を一時的に許可します。作業を BIND と同じサーバーで行うなら、ループバックだけを許可すれば外部に影響しません。
// named.conf の対象ゾーン(作業が終わったら元に戻す)
zone "example.com" {
type primary;
file "/etc/bind/db.example.com";
allow-transfer { 127.0.0.1; 198.51.100.2; }; // 既存のセカンダリも残す
};
sudo named-checkconf && sudo rndc reconfig
# ゾーンごとに csv2 ファイルを作る
mkdir -p ~/maradns-migrate
for z in example.com example.net; do
fetchzone "$z" 127.0.0.1 > ~/maradns-migrate/db."$z"
done
出力されたファイルを開き、SOA・NS・MX・TXT などが揃っているかを確認します。名前は末尾にドットの付いた完全な形で書かれ、レコードごとの TTL も引き継がれます。BIND のゾーンファイルで $ORIGIN や相対名、$GENERATE を使っていても、BIND が解釈した後の結果が届くため、書き換えの手間はかかりません。
一方で、次の点は人の目で確認します。
- csv2 が直接扱えないレコード型:CAA や SSHFP、HTTPS などの新しい型は、版によっては専用の書き方がなく、
RAWという汎用の書き方で出力されるか、出力されないことがあります。BIND のゾーンにある型と、変換後のファイルにある型を照らし合わせます。 - TXT の長い値や特殊な文字:引用符や区切りの扱いが BIND と違うため、SPF・DKIM・DMARC のレコードは変換後の値を元の値と比べます。
- DNSSEC 関連のレコード:署名済みのゾーンから転送すると RRSIG などが含まれます。前の手順で対象から外していれば出てきませんが、出てきた場合はそのゾーンを移行の対象から外します。
手順3:MaraDNS を別のアドレスで動かす
比較のため、MaraDNS は BIND とは別のアドレスで待ち受けます。変換したファイルを chroot_dir に置き、mararc にゾーンを登録します。
# /etc/mararc
ipv4_bind_addresses = "192.0.2.54"
chroot_dir = "/etc/maradns"
maradns_uid = 990
maradns_gid = 990
csv2 = {}
csv2["example.com."] = "db.example.com"
csv2["example.net."] = "db.example.net"
# セカンダリへのゾーン転送を許可する(zoneserver が参照する)
zone_transfer_acl = "198.51.100.2/32"
sudo cp ~/maradns-migrate/db.* /etc/maradns/
sudo systemctl restart maradns
journalctl -u maradns -n 50
maradns_uid と maradns_gid には、MaraDNS を動かす専用ユーザーの番号を入れます(990 は例です)。ゾーン名の末尾のドットと、csv2 = {} の行を忘れると起動に失敗します。起動したら、ログにゾーンの読み込みエラーが出ていないかを確認します。
MaraDNS 本体は UDP の問い合わせだけを扱い、TCP の問い合わせとゾーン転送は zoneserver という別のプログラムが担当します。BIND は1つのプロセスで両方を受けていたので、移行後は zoneserver も起動し、TCP の53番ポートを開けておくことを忘れないようにします。
手順4:BIND と MaraDNS の答えを比べる
BIND(192.0.2.53)と MaraDNS(192.0.2.54)に同じ問い合わせを送り、答えが一致するかを確かめます。
# 変換したファイルから「名前 型」の一覧を作る(~ やコメントを除く)
awk '!/^#/ && NF>=3 {t=$2; if (t ~ /^\+/) t=$3; print $1, t}' ~/maradns-migrate/db.* | sort -u > names.txt
while read -r name type; do
a=$(dig @192.0.2.53 "$name" "$type" +norec +short | sort)
b=$(dig @192.0.2.54 "$name" "$type" +norec +short | sort)
[ "$a" = "$b" ] || echo "DIFF: $name $type"
done < names.txt
一覧の作り方は、fetchzone の出力の形によって調整が要ることがあります。一覧を作ったら中身を見て、名前と型が正しく取れているかを確認してから比べます。
DIFF が出たものは、変換後のファイルを確認します。あわせて次の点も試します。
- 存在しない名前を問い合わせて、両方が
NXDOMAINを返すか。 - ワイルドカードのある名前で、同じ答えが返るか。
digの通常の出力で TTL が同じか(+shortでは TTL が比べられません)。dig @192.0.2.54 example.com AXFRをセカンダリから実行し、zoneserver からの転送が通るか。
手順5:切り替える
切り替えの数日前に、BIND 側で NS と主要なレコードの TTL を短くしておき、元の TTL が切れるのを待ちます。切り替えには2つの方法があります。
- 同じ IP アドレスを引き継ぐ:BIND を止め、mararc の
ipv4_bind_addressesを BIND が使っていたアドレスに変えて MaraDNS と zoneserver を再起動します。レジストラの登録を変えずに済みますが、停止から起動までの短い間は応答が止まります。BIND が OS の再起動で戻ってこないよう、サービスを無効にしておきます(サービス名はnamedやbind9など、ディストリビューションによって異なります)。 - NS を向け替える:MaraDNS を別のサーバーで動かす場合は、レジストラで NS とグルーレコードを変えます。親ゾーンの NS の TTL が切れるまでは BIND にも問い合わせが届くため、BIND は同じ内容のまま止めずに動かします。
セカンダリがある場合は、プライマリのアドレスが変わるならセカンダリ側の設定も更新します。BIND は変更を NOTIFY で知らせていましたが、MaraDNS からの通知は前提にせず、セカンダリが SOA の refresh の間隔で確認しに来る形で考えます。
問題が出たら、BIND を起動し直す(または NS を戻す)だけで元に戻れるよう、BIND の設定とゾーンファイルは移行が落ち着くまで残しておきます。
移行後に変わる運用
- 反映の手順:BIND の
rndc reloadに当たるものはなく、csv2 ファイルを編集したら MaraDNS を再起動して読み込ませます。セカンダリがある場合は、編集のたびに SOA のシリアルを上げます。 - シリアルの管理:
fetchzoneで取り出した SOA には BIND で使っていたシリアルが入っています。同じ形式(例:2026101801)のまま上げ続ければ、セカンダリが値の後退と誤解することはありません。 - 再帰問い合わせ:BIND で社内向けの再帰問い合わせを受けていた場合は、Deadwood を別のアドレスで動かし、
recursive_aclで利用者を BIND のallow-recursionと同じ範囲に絞ります。 - 作業用に広げた許可を戻す:BIND は止めてしまえば影響はありませんが、並行稼働を続ける間は、一時的に追加した
allow-transferを元に戻しておきます。
まとめ
- DNSSEC・view・動的更新・TSIG を使っているゾーンは MaraDNS に向きません。
named-checkconf -pで棚卸ししてから対象を決めます。 - 変換は、BIND からのゾーン転送を
fetchzoneで受けて csv2 にする方法が手間が少なく、新しいレコード型や TXT の値は人の目で確認します。 - MaraDNS は別のアドレスで動かして BIND と答えを比べ、TCP とゾーン転送を担う zoneserver も忘れずに起動します。
- 切り替えは TTL を下げてから行い、BIND の設定は切り戻し用にしばらく残します。