2026年6月13日
2026年6月13日
MaraDNS から NSD へ移行する手順|NSD を zoneserver のセカンダリにして同期し、プライマリに昇格させる
MaraDNS から NSD への移行は、「NSD を MaraDNS(zoneserver)のセカンダリとして動かしてゾーンを受け取る → 答えを比べる → 切り替える → NSD をプライマリに昇格させる」という順に進めると、ゾーンを手で変換せずに済み、切り戻しもしやすくなります。NSD は権威サーバー専用なので、Deadwood が担っていたキャッシュの役割は Unbound など別のリゾルバーに任せます。この記事では、役割の整理、セカンダリとしての同期、比較、切り替え、昇格後の設定までを順に説明します。
内容は MaraDNS 3.5 系と NSD 4 系を前提にしています(2026年10月現在)。NSD の設定項目は版によって追加や既定値の変更があるため、手元の版の man nsd.conf と照らし合わせてください。作業前に mararc と csv2 ファイル一式をバックアップし、検証用のサーバーで一通り試してから本番に移ります。
移行の前に役割を整理する
MaraDNS は役割ごとにプログラムが分かれています。NSD に移すものと、別のソフトに移すものを先に分けます。
- maradns(UDP の権威応答)と zoneserver(TCP の問い合わせとゾーン転送) → NSD。NSD は1つのデーモンで UDP・TCP・ゾーン転送を扱います。
- Deadwood(再帰問い合わせとキャッシュ) → NSD には再帰の機能がありません。同じ NLnet Labs が開発している Unbound を使うのが一般的ですが、Deadwood を使い続けてもかまいません。
社内の端末が MaraDNS のアドレスをリゾルバーとして参照している場合、その問い合わせは Deadwood が受けているはずです。権威と再帰を同じアドレスで動かしていたなら、移行後は別のアドレスに分けるか、Unbound の転送先として NSD を指定する構成にします。
移すゾーンの一覧も作っておきます。
grep -E '^csv2\[' /etc/mararc
手順1:zoneserver で NSD への転送を許可する
NSD はセカンダリとして AXFR でゾーンを受け取ります。MaraDNS 側では zoneserver が動いていること、NSD のアドレスからの転送が許可されていることを確認します。
# /etc/mararc(192.0.2.53 は NSD を動かすサーバーの例)
zone_transfer_acl = "192.0.2.53/32"
mararc を変えたら zoneserver を再起動し、NSD のサーバーから手で AXFR を試します。
dig @192.0.2.1 example.com AXFR +onesoa | head -20
レコードが並べば準備はできています。「Transfer failed.」が返る場合は、zoneserver が起動していない、zone_transfer_acl の範囲に NSD のアドレスが入っていない、TCP 53番がファイアウォールで閉じている、のどれかが多い原因です。
取り出した内容では SOA を確認します。csv2 で SOA を書いていないゾーンは、MaraDNS が合成した SOA が届きます。NSD は SOA のシリアルが増えたときにだけゾーンを取り直すため、シリアルの扱いを把握しておかないと、MaraDNS 側の変更が NSD に届かない原因になります。
手順2:NSD をセカンダリとして設定する
NSD は多くのディストリビューションでパッケージが提供されています。比較のため、最初は MaraDNS とは別のアドレスで待ち受けます。
# /etc/nsd/nsd.conf
server:
ip-address: 192.0.2.53
zonesdir: "/var/lib/nsd"
verbosity: 1
remote-control:
control-enable: yes
control-interface: 127.0.0.1
pattern:
name: "from-maradns"
request-xfr: AXFR 192.0.2.1 NOKEY
allow-notify: 192.0.2.1 NOKEY
zone:
name: "example.com"
zonefile: "example.com.zone"
include-pattern: "from-maradns"
zone:
name: "example.net"
zonefile: "example.net.zone"
include-pattern: "from-maradns"
request-xfr の先頭の AXFR は、IXFR を試さずに最初から AXFR で受け取る指定です。MaraDNS の zoneserver は差分転送(IXFR)を前提にしていないため、明示しておくとログが読みやすくなります。MaraDNS は変更の通知(NOTIFY)を送らない前提なので、NSD は SOA の refresh の間隔で更新を確認しに行きます。共通の設定を pattern にまとめておくと、昇格のときにも書き換える箇所が少なくて済みます。
sudo nsd-control-setup # 制御用の鍵を作る(パッケージで作成済みの場合もある)
sudo nsd-checkconf /etc/nsd/nsd.conf
sudo systemctl restart nsd
sudo nsd-control zonestatus example.com
nsd-checkconf が何も出さなければ設定の書式は問題ありません。zonestatus で受け取ったシリアルが表示されれば同期できています。受け取れていない場合は journalctl -u nsd で転送のエラーを確認し、sudo nsd-control force_transfer example.com でシリアルに関係なく取り直せます。
手順3:MaraDNS と NSD の答えを比べる
MaraDNS(192.0.2.1)と NSD(192.0.2.53)に同じ問い合わせを送り、答えが一致するかを確かめます。名前と種類の一覧は、手順1の AXFR の結果から作ります。
dig @192.0.2.1 example.com AXFR +onesoa +nocmd +nostats \
| awk '!/^;/ && NF>=5 {print $1, $4}' | 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.53 "$name" "$type" +norec +short | sort)
[ "$a" = "$b" ] || echo "DIFF: $name $type"
done < names.txt
NSD はゾーン転送で同じデータを受け取っているので、通常のレコードで差が出ることは少ないはずです。差が出やすいのは次のような「データではなく動き」の部分です。
- 存在しない名前:NXDOMAIN と SOA が返るか。
- ワイルドカード:NSD は標準の仕様どおりに動くため、MaraDNS 独自の挙動に頼っていた名前で差が出ることがあります。
- TCP の応答:
dig +tcpでも同じ答えが返るか。 - aa フラグ:
digのflagsにaaが付いているか。
手順4:切り替えと切り戻し
切り替えの数日前に、MaraDNS 側で NS と主要なレコードの TTL を短くします。MaraDNS はゾーンを起動時に読むので、csv2 ファイルを変えたら MaraDNS を再起動し、NSD 側で force_transfer して新しい TTL が届いたことを確認します。元の TTL が切れるのを待ってから切り替えます。
- 同じ IP アドレスを引き継ぐ:MaraDNS と zoneserver を止めて自動起動を無効にし、
nsd.confのip-addressを元のアドレスに変えて NSD を再起動します。レジストラの登録は変えずに済みます。 - NS を向け替える:NSD を別のサーバーで動かし続ける場合は、レジストラで NS とグルーレコードを変えます。親ゾーンの NS の TTL が切れるまでは MaraDNS にも問い合わせが届くため、しばらくは止めません。
同じアドレスを引き継ぐ場合、MaraDNS を止めた時点で NSD は転送元を失います。NSD は受け取ったゾーンを保持して応答を続けますが、手順5の昇格を早めに行います。問題が出たら NSD を止めて MaraDNS と zoneserver を起動し直せば元に戻せます。mararc と csv2 ファイルは、移行が落ち着くまで消さずに残します。
手順5:NSD をプライマリに昇格させる
セカンダリのままでは、NSD はゾーンの更新を転送元に頼り続けます。受け取ったゾーンをファイルに書き出し、NSD 自身が持つゾーンとして扱うように設定を変えます。
sudo nsd-control write example.com
sudo nsd-checkzone example.com /var/lib/nsd/example.com.zone
nsd-control write は、メモリ上のゾーンを zonefile に指定したファイルへ書き出します。nsd-checkzone でエラーが出ないことを確認したら、nsd.conf から include-pattern: "from-maradns" の行を外し、nsd-checkconf で検査してから NSD を再起動します。以後はこのファイルを編集し、SOA のシリアルを上げてから sudo nsd-control reload example.com で読み込ませます。書き出したファイルは MaraDNS の csv2 とは別物なので、編集はこちらに一本化します。
昇格後にセカンダリを置く場合は、NOTIFY と TSIG を設定します。
key:
name: "xfr-key"
algorithm: hmac-sha256
secret: "your-base64-secret"
pattern:
name: "to-secondary"
notify: 198.51.100.2 xfr-key
provide-xfr: 198.51.100.2 xfr-key
zone:
name: "example.com"
zonefile: "example.com.zone"
include-pattern: "to-secondary"
secret には openssl rand -base64 32 などで作った値を入れ、セカンダリ側にも同じ鍵を設定します。鍵そのものなので、nsd.conf の権限を絞り、バージョン管理に入れる場合は鍵を別ファイルに分けて除外します。作業用に広げた MaraDNS の zone_transfer_acl も、この時点で不要になります。
DNSSEC を使う場合、NSD は署名済みのゾーンを配信する役割で、鍵の管理や再署名は行いません。ldns-signzone などで署名するか、OpenDNSSEC のような署名の仕組みと組み合わせます。署名の期限切れは名前解決の停止につながるため、移行とは別の作業として、手順と監視を決めてから始めます。
まとめ
- NSD は maradns と zoneserver の役割を引き継ぎます。Deadwood の再帰とキャッシュは Unbound などに任せます。
- NSD を
request-xfr: AXFRで zoneserver のセカンダリにすると、csv2 を手で変換せずにゾーンを受け取れます。 - 答えを比べ、TTL を下げてから、IP の引き継ぎか NS の向け替えで切り替えます。
- 切り替え後は
nsd-control writeでゾーンを書き出し、転送の設定を外してプライマリに昇格させます。