2026年6月14日
2026年6月14日
MaraDNS から Knot DNS へ移行する手順|zoneserver からゾーンを取り出し、NOTIFY・TSIG・DNSSEC は段階的に有効にする
MaraDNS から Knot DNS への移行は、「MaraDNS の zoneserver からゾーン転送(AXFR)でゾーンを取り出す → Knot DNS を別のアドレスで動かして答えを比べる → 切り替える → 落ち着いてから NOTIFY・TSIG・DNSSEC など Knot で使えるようになった機能を順に有効にする」という段取りで進めると、問題が起きたときに原因を絞り込みやすくなります。csv2 形式のファイルを手で書き換えるより、MaraDNS 自身が解釈した結果を受け取るほうが誤りが入りにくい、というのが取り出し方の考え方です。この記事では、役割の対応づけ、変換、Knot の設定、比較と切り替え、移行後に有効にする機能の順に説明します。
内容は MaraDNS 3.5 系と Knot DNS 3.x 系を前提にしています(2026年10月現在)。Knot の設定項目は版ごとに追加や名前の変更があるため、手元の版の公式ドキュメント(Knot DNS の Reference manual)と照らし合わせてください。作業前には mararc とゾーンファイル一式をバックアップし、検証用のサーバーで手順を一通り試します。
移行の前に役割を対応づける
MaraDNS は役割ごとにプログラムが分かれています。Knot DNS は権威サーバー専用なので、どれを Knot に移し、どれを別のソフトに任せるかを先に決めます。
- maradns(UDP の権威応答)と zoneserver(TCP の問い合わせとゾーン転送) → Knot DNS。Knot は1つのプロセスで UDP・TCP・ゾーン転送を扱うため、2つのプログラムが1つにまとまります。
- Deadwood(キャッシュサーバー) → Knot DNS では置き換えられません。Knot Resolver や Unbound などのリゾルバーを別に用意するか、Deadwood をそのまま使い続けます。
あわせて、mararc から移すゾーンの一覧を作ります。
grep -E '^csv2\[' /etc/mararc
csv2["ゾーン名."] = "ファイル名" の行がゾーンの数だけ並びます。mararc に、どのゾーンにも当てはまらない問い合わせに答える既定のゾーンファイル(csv2_default_zonefile)のような特殊な設定がある場合は、その動きを Knot で再現できるかを個別に検討します。ゾーン転送では取り出せない動きだからです。
手順1:zoneserver からゾーンを取り出す
MaraDNS の zoneserver が動いていれば、dig で AXFR を受けて、そのまま一般的なゾーンファイルとして保存できます。mararc で作業用ホストからの転送を許可します(作業が終わったら元に戻します)。
# /etc/mararc に追加(192.0.2.50 は作業用ホストの例)
zone_transfer_acl = "192.0.2.50/32"
zoneserver を再起動してから、作業用ホストで次のように実行します。
mkdir -p ~/knot-migrate
for z in example.com example.net; do
dig @192.0.2.1 "$z" AXFR +onesoa +nocmd +nostats > ~/knot-migrate/"$z".zone
done
+onesoa は、AXFR の最後にもう一度送られてくる SOA を省くオプションです。これを付けないと、同じ SOA が2つあるファイルになり、Knot が読み込むときにエラーになります。
取り出したファイルでは、次の点を確認します。
- SOA と NS:csv2 で SOA や NS を書いていなかったゾーンは、MaraDNS が合成した値が届きます。シリアルや管理者のアドレスが意図どおりかを見て、必要なら書き直します。
- TTL:csv2 で TTL を省略していたレコードは、MaraDNS の既定値が入っています。移行を機に値を見直すなら、切り替え後に変えます。切り替えと同時に変えると、比較で差が出て原因を追いにくくなります。
- ワイルドカード:Knot は標準の仕様どおりに動くため、細かな挙動が MaraDNS と違うことがあります。比較の段階で重点的に確認します。
手順2:Knot DNS を別のアドレスで動かす
Knot DNS は多くのディストリビューションでパッケージとして提供されています。新しい版が必要な場合は、開発元(CZ.NIC)が案内しているリポジトリを使います。比較のため、最初は MaraDNS とは別のアドレスで待ち受けます。
# /etc/knot/knot.conf
server:
listen: 192.0.2.54@53
rundir: "/run/knot"
user: knot:knot
log:
- target: syslog
any: info
template:
- id: default
storage: "/var/lib/knot/zones"
file: "%s.zone"
zone:
- domain: example.com
- domain: example.net
template の default に書いた内容は、すべてのゾーンに適用されます。file の %s はゾーン名に置き換わるので、example.com は /var/lib/knot/zones/example.com.zone を読みます。ゾーンが増えても、zone に1行足すだけで済みます。
sudo mkdir -p /var/lib/knot/zones
sudo cp ~/knot-migrate/*.zone /var/lib/knot/zones/
sudo chown -R knot:knot /var/lib/knot/zones
# ゾーンファイルと設定を検査してから起動する
kzonecheck -o example.com /var/lib/knot/zones/example.com.zone
sudo knotc conf-check
sudo systemctl restart knot
sudo knotc zone-status
kzonecheck が何も問題を報告しなければ、ゾーンファイルは読み込めます。knotc zone-status で各ゾーンの状態と読み込んだシリアルを確認できます。起動しない場合は journalctl -u knot でエラーの行を見ます。ゾーンディレクトリの所有者が knot になっていないと、読み込みや書き出しに失敗することがあります。
手順3:MaraDNS と Knot の答えを比べる
MaraDNS(192.0.2.1)と Knot(192.0.2.54)に同じ問い合わせを送り、答えが一致するかを確かめます。
awk '!/^;/ && NF>=5 {print $1, $4}' ~/knot-migrate/*.zone | sort -u > names.txt
while read -r name type; do
a=$(dig @192.0.2.1 "$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
SOA のシリアルを書き直した場合、SOA に差が出るのは正常です。それ以外の DIFF は、取り出したファイルを確認します。存在しない名前で NXDOMAIN が返るか、flags に aa が付いているか、TCP(dig +tcp)でも同じ答えが返るかも試します。MaraDNS では TCP を zoneserver が担当していたので、TCP の答えは別に確認しておくと安心です。
手順4:切り替えと切り戻し
切り替えの数日前に、MaraDNS 側で NS と主要なレコードの TTL を短くします。MaraDNS はゾーンファイルを起動時に読むため、変更したら MaraDNS を再起動します。元の TTL が切れるのを待ってから切り替えます。
- 同じ IP アドレスを引き継ぐ:MaraDNS と zoneserver を止めて自動起動を無効にし、
knot.confのlistenを元のアドレスに変えて Knot を再起動します。レジストラの登録は変えずに済みます。 - NS を向け替える:Knot を別のサーバーで動かす場合は、レジストラで NS とグルーレコードを変えます。親ゾーンの NS の TTL が切れるまでは MaraDNS にも問い合わせが届くため、同じ内容のまま動かし続けます。
問題が出たら、Knot を止めて MaraDNS と zoneserver を起動し直す(または NS を戻す)ことで元に戻せます。mararc と csv2 ファイルは、移行が落ち着くまで消さずに残しておきます。作業用に広げた zone_transfer_acl は、切り替え後に元に戻します。
移行後に有効にする機能
MaraDNS では使えなかった機能が Knot では使えるようになります。切り替えが落ち着いてから、1つずつ有効にします。一度に変えると、問題が起きたときにどの変更が原因か分からなくなります。
NOTIFY と TSIG でセカンダリに配る
MaraDNS は変更の通知を送らない前提で運用していたため、セカンダリは SOA の refresh の間隔で確認しに来ていました。Knot では NOTIFY で変更をすぐに知らせ、TSIG の鍵でゾーン転送を認証できます。
# TSIG の鍵を作る(出力された key: の部分を knot.conf に貼る)
keymgr -t xfr-secondary hmac-sha256
key:
- id: xfr-secondary
algorithm: hmac-sha256
secret: your-generated-secret
remote:
- id: secondary
address: 198.51.100.2@53
key: xfr-secondary
acl:
- id: transfer-to-secondary
address: 198.51.100.2
key: xfr-secondary
action: transfer
template:
- id: default
storage: "/var/lib/knot/zones"
file: "%s.zone"
notify: secondary
acl: transfer-to-secondary
セカンダリ側にも同じ鍵を設定します。secret は鍵そのものなので、設定ファイルの権限を絞り、バージョン管理に入れる場合は別ファイルに分けて除外します。設定を変えたら knotc conf-check で検査し、knotc reload で読み込ませます。
ゾーンの更新手順を決める
Knot では再起動せずにゾーンを読み直せます。ゾーンファイルを編集したら、SOA のシリアルを上げてから次を実行します。
kzonecheck -o example.com /var/lib/knot/zones/example.com.zone
sudo knotc zone-reload example.com
シリアルを自動で決める設定(serial-policy)もありますが、手で編集するファイルとの組み合わせ方には注意が要ります。最初は手でシリアルを上げる運用から始めるのが分かりやすいでしょう。
DNSSEC の署名を有効にする
DNSSEC は、移行の最後に別の作業として行います。ゾーンに dnssec-signing: on を設定すると、Knot が鍵の生成と署名を自動で行います。
zone:
- domain: example.com
dnssec-signing: on
署名を有効にすると、Knot は署名済みの内容を管理するようになります。手で編集するゾーンファイルを署名前の状態のまま保ちたい場合は、zonefile-sync: -1、zonefile-load: difference-no-serial、journal-content: all の組み合わせが公式のドキュメントで案内されています。設定の意味を確認してから使ってください。
署名ができたら、keymgr example.com ds などで DS レコードの値を確認し、レジストラに登録します。DS を登録する前に署名をやめたり鍵を消したりすると名前解決ができなくなるおそれがあるため、DS の登録と鍵の切り替えの手順は、Knot のドキュメントで確認してから進めます。
まとめ
- Knot DNS は maradns と zoneserver の役割をまとめて引き継ぎます。Deadwood の役割は別のリゾルバーに任せます。
- ゾーンは zoneserver から
dig AXFR +onesoaで取り出し、合成された SOA・NS や TTL の既定値を確認します。 - Knot は別のアドレスで動かし、
kzonecheck・knotc conf-checkで検査してから全レコードを比べ、TTL を下げてから切り替えます。 - NOTIFY・TSIG・DNSSEC は、切り替えが落ち着いてから1つずつ有効にします。