2026年6月12日
2026年6月12日
djbdns から Knot DNS へ移行する手順|Knot を一時的なセカンダリにしてゾーンを引き継ぐ
djbdns(tinydns)から Knot DNS への移行は、Knot をいったん「axfrdns からゾーン転送を受けるセカンダリ」として立ち上げ、応答が一致することを確かめてから、プライマリに昇格させて問い合わせの向き先を切り替える流れで進めると、変換スクリプトを書かずに済みます。この記事では、移行前の確認、axfrdns と Knot の設定、応答の突き合わせ、プライマリへの昇格、切り替えと切り戻しまでを順に説明します。
移行前に確認すること
djbdns は 1.05 以降、作者による公式な更新がなく、DNSSEC や EDNS0 に対応していません(2026年10月現在)。Knot DNS は CZ.NIC が開発を続けている権威DNS専用のサーバーで、DNSSEC の自動署名、NOTIFY を使ったセカンダリへの即時配信、TCP での応答を1つのプログラムで扱えます。手元の環境で使えるバージョンは、ディストリビューションのパッケージか CZ.NIC が案内しているリポジトリで確認してください。この記事の設定例は 3.x 系の書式を前提にしています。
作業を始める前に、次の3点を確かめます。
- どのサービスを移すのか:djbdns には権威サーバーの tinydns、TCP とゾーン転送を担う axfrdns、キャッシュサーバーの dnscache が含まれます。Knot は権威サーバーなので、置き換えの対象は tinydns と axfrdns です。dnscache を使っている場合は、Unbound などのキャッシュサーバーへの移行を別に計画します。
- Knot で同じ動きにならない書き方:data ファイルの
%で始まる行(問い合わせ元によって答えを変えるロケーション機能)や、行の末尾に付けた有効期限のタイムスタンプは、ゾーン転送では「転送した時点の答え」しか引き継げません。grep -n '^%' dataでロケーションの有無を確認し、使っている場合は移行後の設計を先に決めておきます。 - ワイルドカード:tinydns のワイルドカードは、細かな条件で一般的なDNSサーバーと答えが変わる場合があります。
*を含む行があれば、その配下の名前を比較の対象に加えます。
data ファイルと data.cdb はコピーを取っておきます。移行が終わるまではレコードの変更をできるだけ止めておくと、比較と切り戻しが簡単になります。
手順1:axfrdns で Knot からの転送を許可する
Knot はゾーン転送(AXFR)でゾーンを受け取ります。tinydns 自体は UDP の応答しか行わないため、転送には axfrdns が必要です。axfrdns は tinydns と同じ IP アドレスの TCP 53 番で待ち受けて、tinydns の data.cdb の内容を送ります。
axfrdns がまだない場合は、tinydns のディレクトリを指定して作ります。ディレクトリやユーザー名は環境に合わせて読み替えてください。
# axfrdns と dnslog のユーザーがなければ作成しておく
sudo axfrdns-conf axfrdns dnslog /etc/axfrdns /etc/tinydns 192.0.2.53
sudo ln -s /etc/axfrdns /etc/service/axfrdns
転送を許可する相手は /etc/axfrdns/tcp に書きます。Knot を動かすサーバー(例では 198.51.100.20)だけに、移行するゾーンの転送を許可します。
198.51.100.20:allow,AXFR="example.com/example.net"
:allow,AXFR=""
1行目は Knot のサーバーに2つのゾーンの転送を許可し、2行目はそれ以外の相手に TCP での通常の問い合わせだけを許可します(AXFR="" は転送を1つも許可しない指定です)。書き換えたら cd /etc/axfrdns && sudo make で tcp.cdb を作り直します。make を忘れると、変更が反映されません。
手順2:Knot DNS をセカンダリとして設定する
Knot は、可能であれば tinydns とは別のサーバーか別の IP アドレスで動かします。同じアドレスの 53 番ポートは取り合いになるためです。/etc/knot/knot.conf の例です。
server:
listen: [ 198.51.100.20@53 ]
log:
- target: syslog
any: info
remote:
- id: tinydns
address: 192.0.2.53@53
acl:
- id: notify_from_tinydns
address: 192.0.2.53
action: notify
template:
- id: default
storage: /var/lib/knot
file: "%s.zone"
zone:
- domain: example.com
master: tinydns
acl: notify_from_tinydns
- domain: example.net
master: tinydns
acl: notify_from_tinydns
remote は相手サーバーの住所録で、zone の master に書いた相手からゾーンを受け取ります。axfrdns は TSIG に対応していないため、ここでは鍵を使わず、手順1の IP アドレスによる制限で守っています。また tinydns は NOTIFY を送らないので、acl の行は将来の構成変更に備えた記述と考えてください。
設定を確認して起動します。
sudo knotc conf-check
sudo systemctl enable --now knot
sudo knotc zone-status
zone-status で各ゾーンのシリアルが表示されれば、転送は成功しています。表示されない場合は、journalctl -u knot で転送のエラーを、axfrdns 側は /etc/axfrdns/log/main/current で接続の記録を確認します。拒否されている場合は tcp ファイルの IP アドレスか make の実行漏れ、接続できない場合はファイアウォールで TCP 53 番が閉じている、の順に疑うと早く見つかります。
tinydns は NOTIFY を送らないため、Knot は SOA のリフレッシュ間隔が来るまで変更を取りに行きません。比較の途中で data を更新した場合は、sudo knotc zone-retransfer example.com で全体を取り直します。
手順3:応答を突き合わせる
Knot が受け取ったゾーンは /var/lib/knot/example.com.zone に書き出されます。ここから名前とレコードの種類の一覧を作り、両方のサーバーに同じ問い合わせをして結果を比べます。
#!/bin/sh
# 使い方: ./compare.sh example.com
ZONE="$1"
OLD=192.0.2.53 # 現行の tinydns
NEW=198.51.100.20 # Knot DNS
awk '!/^;/ && NF>=3 { for (i=2; i<=NF; i++) if ($i ~ /^(A|AAAA|NS|MX|TXT|CNAME|PTR|SRV|CAA|SOA)$/) { print $1, $i; break } }' \
/var/lib/knot/"$ZONE".zone | sort -u | while read -r name type; do
a=$(dig @"$OLD" "$name" "$type" +short +norec | sort)
b=$(dig @"$NEW" "$name" "$type" +short +norec | sort)
[ "$a" = "$b" ] || echo "DIFF: $name $type"
done
ファイルの書式によって列の位置が変わることがあるため、awk では種類の欄を探す書き方にしています。DIFF が1行も出なければ、一覧にある名前については同じ答えが返っています。
一覧に出てこない名前も確かめます。存在しない名前(dig @198.51.100.20 nothing.example.com +norec)で両方とも NXDOMAIN が返るか、ワイルドカード配下の名前で同じ答えが返るか、flags に aa が付いているかを見ます。aa が付いていれば、Knot がそのゾーンの権威として答えています。ロケーションを使っていた場合は、問い合わせ元を変えて試さないと差が見えない点に注意してください。
手順4:Knot をプライマリに昇格させる
比較で問題がなければ、Knot を tinydns から切り離してプライマリにします。まず、受け取った内容がファイルに書き出されていることを確かめます。
sudo knotc zone-flush example.com
sudo kzonecheck -o example.com /var/lib/knot/example.com.zone
続いて knot.conf の各ゾーンから master と acl の行を削除し、設定を読み直します。
zone:
- domain: example.com
- domain: example.net
sudo knotc conf-check && sudo knotc reload
sudo knotc zone-status example.com
これで、Knot はゾーンファイルを元に自分で答えるようになります。昇格後のゾーンファイルは、ここから手で管理する正本になります。Git などで履歴を残すと、誤った変更を戻しやすくなります。
注意したいのは SOA のシリアルです。tinydns は data ファイルの更新時刻(UNIX 時刻)をシリアルに使うことが多く、昇格直後のシリアルもその値のままです。この先は変更のたびに自分でシリアルを上げる必要があります。2026101801 のような日付形式に切り替えると分かりやすく、日付形式の値は現在の UNIX 時刻より大きいため、既存のセカンダリが「シリアルが下がった」と判断することもありません。Knot にはシリアルの扱いを決める serial-policy などの設定もありますが、効く場面がバージョンや他の設定によって変わるため、公式ドキュメントで確認してから使います。
手順5:切り替えと切り戻し
切り替えの方法は2つあります。
- 方法A:IP アドレスを付け替える:tinydns が使っていたアドレスを Knot のサーバーに移します。レジストラの NS やグルーレコードを変えずに済む一方、アドレスを移す間は応答が途切れます。
- 方法B:NS を変える:Knot のサーバー名を NS として追加し、レジストラ側の登録と、ゾーン内の NS レコードを書き換えます。旧サーバーは NS の TTL が切れるまで動かし続けます。止まる時間はありませんが、反映には時間がかかります。
旧サーバーの tinydns と axfrdns を止めるときは、OS の再起動で daemontools が起動し直さないように down ファイルを置きます。
sudo svc -d /etc/service/tinydns /etc/service/axfrdns
sudo touch /etc/tinydns/down /etc/axfrdns/down
切り戻しが必要になったら、down ファイルを削除して svc -u で起動し直し、方法Aならアドレスを、方法Bなら NS を元に戻します。data と data.cdb を消さずに残しておけば、すぐに元の状態へ戻れます。片付けは、切り戻しの可能性がなくなってから行います。
移行後にできるようになること
Knot に移ると、セカンダリへの NOTIFY と TSIG による転送の保護、DNSSEC の自動署名が使えるようになります。ただし DNSSEC は、署名を有効にしてから DS レコードをレジストラに登録する順番を誤ると名前解決が失敗します。移行直後に一度に変えず、ゾーンの引き継ぎが落ち着いてから別の作業として進めるほうが、問題が起きたときに原因を切り分けやすくなります。
まとめ
- Knot を axfrdns からゾーン転送を受けるセカンダリとして立てると、data ファイルを手で変換せずにゾーンを引き継げます。
- axfrdns の tcp ファイルで Knot のサーバーだけに転送を許可し、変更後は
makeで反映します。 - 名前と種類の一覧から両方のサーバーに同じ問い合わせをして比べ、NXDOMAIN やワイルドカード、ロケーションも個別に確かめます。
zone-flushでゾーンファイルを書き出し、masterを外してプライマリにします。シリアルは日付形式に切り替えると管理しやすくなります。- 旧サーバーは
downファイルを置いて止め、data と data.cdb は切り戻しの可能性がなくなるまで残します。