2026年6月12日

2026年6月12日

djbdns で複数ゾーンを管理する設定|data をゾーンごとのファイルに分け、結合・検査・反映を make にまとめる

djbdns(tinydns)で扱うゾーンが増えてきたら、data ファイルを「ゾーンごとのファイル」に分け、make で結合と検査と data.cdb の生成をまとめて行う構成にすると、編集の取り違えや1か所の書き間違いで全ゾーンの更新が止まる事態を減らせます。この記事では、ディレクトリ構成、Makefile、追加前の自動検査、ゾーンの追加と削除の順番、axfrdns の許可の管理までを説明します。data ファイルの記号そのものの書き方は扱わず、ゾーンが多いときの運用の組み立てに絞ります。

tinydns は複数ゾーンをどう扱うか

tinydns は、すべてのゾーンを1つの data ファイルにまとめて持ちます。make(内部で tinydns-data)を実行すると data が data.cdb に変換され、tinydns は問い合わせのたびに data.cdb を読むため、再起動しなくても新しい内容で答えます。ゾーンの起点になるのは . か Z で始まる行で、それ以外の行は単に名前とレコードの組です。

この仕組みには、ゾーンが増えたときに困る点が2つあります。

  • 1行の誤りで全ゾーンが止まる:tinydns-data は data の中に書式の誤りを見つけると data.cdb を作り直さずに終了します。古い data.cdb が残るので応答は止まりませんが、関係のないゾーンの変更まで反映されなくなります。
  • どの行がどのゾーンのものか分かりにくい:数百行の data では、別の担当者が書いた行を誤って消したり、同じ名前を二重に定義したりしやすくなります。

ゾーンごとにファイルを分け、結合する前に検査を挟むと、この2つを抑えられます。djbdns は 1.05 以降、公式な更新がない点(2026年10月現在)も踏まえ、運用の仕組みは自分たちで整えておく必要があります。

ディレクトリ構成を決める

tinydns のサービスディレクトリ(例: /etc/tinydns/root)の下に zones ディレクトリを作り、1ゾーン1ファイルで置きます。ファイル名はゾーン名に .data を付けた形にそろえると、後で説明する検査がファイル名からゾーンを判断できます。

/etc/tinydns/root/
├── Makefile
├── check.sh
├── data          ← 生成物(直接編集しない)
├── data.cdb      ← 生成物
└── zones/
    ├── 00-common.data            ← ロケーション(%)や共通のネームサーバーのA
    ├── example.com.data
    ├── example.net.data
    └── 2.0.192.in-addr.arpa.data

00- で始まるファイルは、特定のゾーンに属さない行を置く場所です。% で始まるロケーションの定義や、全ゾーンで共有するネームサーバー名の A レコードをここに書きます。

ゾーンが多い場合は、ネームサーバー名を1つのドメインの下にまとめると管理が楽になります。. の行の3番目の項目にドットを含む名前を書くと、tinydns-data はその名前をそのまま NS に使い、A レコードを自動では作りません。

# zones/example.net.data
.example.net::ns1.example.com:259200
.example.net::ns2.example.com:259200
+www.example.net:192.0.2.80:3600
# zones/00-common.data
+ns1.example.com:192.0.2.53:259200
+ns2.example.com:198.51.100.53:259200

こうしておくと、ネームサーバーのアドレスを変えるときに直す場所が1つで済みます。

Makefile で結合とビルドをまとめる

tinydns-conf が作る Makefile は data.cdb を作るだけなので、結合と検査の手順を加えます。行頭はスペースではなくタブです。tinydns-data のパスは、ソースから入れた場合の例です。パッケージで入れた場合は which tinydns-data で確認して置き換えます。

# data は zones/*.data から生成する。data を直接編集しないこと
data.cdb: data
	/usr/local/bin/tinydns-data

data: FORCE
	sh ./check.sh
	cat zones/*.data > data.tmp
	if cmp -s data.tmp data; then rm -f data.tmp; else mv data.tmp data; fi

FORCE:

data は毎回作り直しますが、内容が変わったときだけ置き換えています。置き換えなければ data の更新時刻が変わらず、data.cdb も作り直されません。tinydns は data の更新時刻を SOA のシリアルに使うことが多いため、中身が同じなのにシリアルだけ上がってセカンダリが転送をやり直す、という無駄を防げます。

結合する前に検査する

check.sh では、ゾーンが増えたときに起きやすい3つの誤りを調べます。検査で問題が見つかると make が止まり、data は置き換えられません。

#!/bin/sh
# zones/ のファイルを結合する前の検査
cd "$(dirname "$0")/zones" || exit 1
status=0

# 1. ファイル名のゾーンの外にある名前が混ざっていないか
for f in *.data; do
  zone=${f%.data}
  case "$f" in 00-*) continue ;; esac
  awk -F: -v z="$zone" -v f="$f" '
    /^[#%]/ || NF == 0 { next }
    { name = tolower(substr($1, 2)); sub(/\.$/, "", name)
      if (name != z && substr(name, length(name) - length(z)) != "." z) {
        printf "%s:%d: %s はゾーン %s の外にあります\n", f, NR, name, z; bad = 1 } }
    END { exit bad }' "$f" || status=1
done

# 2. 同じゾーンの起点(. と Z の行)が複数のファイルにないか
dup=$(grep -H '^[.Z]' *.data | awk -F: '{ print substr($2, 2), $1 }' | sort -u \
  | awk '{ c[$1]++ } END { for (n in c) if (c[n] > 1) print n }')
[ -z "$dup" ] || { echo "起点が複数のファイルにあるゾーン: $dup"; status=1; }

# 3. 同じ IP アドレスに = の行が2つ以上ないか(PTR が二重になる)
ptr=$(grep -h '^=' *.data | cut -d: -f2 | sort | uniq -d)
[ -z "$ptr" ] || { echo "= の行が重複している IP: $ptr"; status=1; }

exit $status

1つ目の検査は、例えば example.net.data に +www.example.com:... と書いてしまった誤りを見つけます。2つ目は、ゾーンを別のファイルに移したときに古いファイルにも起点が残っている状態を見つけます。同じゾーンに NS が2台あるときは . の行が2行になりますが、同じファイルの中なら問題にしません。3つ目は、=(A と PTR を同時に作る行)で同じアドレスを2回使い、逆引きが2つ返る誤りを見つけます。

反映と確認

zones のファイルを編集したら、サービスディレクトリで make を実行します。

cd /etc/tinydns/root
sudo make
# data.cdb を直接引いて、ネットワークを通さずに確認する
tinydns-get a www.example.net
# 外から tinydns に問い合わせる
dig @192.0.2.53 www.example.net A +norec
dig @192.0.2.53 example.net SOA +norec

tinydns-get はカレントディレクトリの data.cdb を読んで答えを表示するコマンドで、tinydns を経由せずに変換結果を確かめられます。dig の結果で flags に aa が付き、SOA のシリアルが更新されていれば反映できています。make がエラーで止まった場合は、出力されたファイル名と行番号を見て直します。tinydns-data の誤りは、data の何行目かで表示されるため、結合した data を sed -n '行番号p' data で見るとどのゾーンの行か分かります。

ゾーンの追加と削除の順番

ゾーンを追加するときは、次の順に進めます。

  1. zones/ゾーン名.data を作り、. の行と必要なレコードを書きます。
  2. make で検査と反映を行い、dig で自分のサーバーが答えることを確かめます。
  3. axfrdns でセカンダリに転送している場合は、/etc/axfrdns/tcp の AXFR="example.com/example.net" のようなスラッシュ区切りの一覧に新しいゾーンを加え、/etc/axfrdns で make を実行します。この一覧に入っていないゾーンは転送されません。
  4. 最後に、レジストラでそのドメインの NS をこのサーバーに向けます。

順番を逆にして先に NS を向けると、ゾーンが用意されるまでの間、問い合わせに答えられない時間ができます。

削除はこの逆です。先にレジストラ側で NS を別のサーバーへ移し、NS の TTL が切れるのを待ってから、ファイルを zones から外して make します。外したファイルはすぐに消さず、別のディレクトリに保管しておくと、誤って消したときに戻せます。セカンダリにも同じゾーンが残っているので、そちらの設定からも外します。

Git で管理する

zones ディレクトリと Makefile、check.sh を Git で管理すると、誰がいつどのゾーンを変えたかを追えます。生成物の data と data.cdb は管理対象から外します。変更を本番に入れる前に、検証用のサーバーで同じ make を実行して検査を通しておくと、誤りに早く気付けます。作業前には、現在の data と data.cdb のコピーを取っておきます。

まとめ

  • tinydns は全ゾーンを1つの data にまとめて持つため、ゾーンが増えたら1ゾーン1ファイルに分けて結合する構成にします。
  • Makefile で検査・結合・data.cdb の生成をまとめ、内容が変わったときだけ data を置き換えると、無駄なシリアルの更新を防げます。
  • 検査では、ゾーン外の名前・起点の重複・PTR の重複を結合前に見つけます。
  • ゾーンの追加は「ファイル作成 → make → axfrdns の許可 → NS の変更」、削除はその逆の順に進めます。
  • zones と Makefile を Git で管理し、data と data.cdb は生成物として扱います。

お気軽にご相談ください

お見積りへ お問い合わせへ
▲