2026年6月13日
2026年6月13日
TinyDNS から dnsmasq へ移行する手順|data ファイルの書き換え・並行稼働での比較・切り戻しまで
社内 LAN の名前を TinyDNS(djbdns)で答えている環境なら、data ファイルのレコードを dnsmasq の設定行に書き換え、別ポートで並行稼働させて答えを比べてから切り替えることで、安全に dnsmasq へ移行できます。ただし dnsmasq は転送・キャッシュと小規模なローカル名の応答を得意とするソフトで、インターネットに公開する権威 DNS の置き換えには向きません。この記事では、移行してよいケースの見分け方、レコードの対応表、比較用のスクリプト、切り替えと切り戻しの手順を説明します。
移行の前に:TinyDNS が担っている役割を確かめる
TinyDNS は問い合わせに対して自分の持つゾーンの答えだけを返す権威 DNS サーバーです。djbdns では、利用者からの名前解決はキャッシュサーバーの dnscache が受け、社内ドメインの問い合わせだけを TinyDNS に回す構成がよく使われていました。dnscache の root/servers/ に社内ドメイン名のファイルがあり、その中に TinyDNS のアドレスが書かれていれば、この構成です。
dnsmasq への移行が向いているのは、次のような場合です。
- TinyDNS が社内 LAN 向けの名前(
example.lanなど)だけを答えている - 利用者は dnscache などのキャッシュサーバー経由で名前解決している
- レコードの数が多くなく、A・CNAME・MX・TXT 程度で足りている
この構成なら、dnsmasq 1つで「社内名の応答」と「それ以外の転送・キャッシュ」の両方を置き換えられます。以降の例では、端末が使う dnscache が 192.168.1.53 で、TinyDNS が 127.0.0.2 で待ち受けている構成とします(TinyDNS と dnscache は同じアドレスの 53 番を共有できないため、このように分けるのが一般的です)。
一方、レジストラに登録した NS として TinyDNS がインターネットに公開ゾーンを提供している場合は、dnsmasq を選ぶのは避けたほうが無難です。dnsmasq にも権威応答を返すモード(auth-server や auth-zone などの設定)はありますが、単純な構成を想定した機能で、多数のゾーンやセカンダリとの運用を前提とした NSD・Knot DNS・BIND・PowerDNS のほうが適しています。
手順1:data ファイルを棚卸しする
TinyDNS のレコードは、一般に /etc/tinydns/root/data(環境によっては /service/tinydns/root/data)に1行1レコードで書かれ、make で data.cdb に変換して読み込まれます。まず data ファイルをバックアップし、どの種類の行があるかを数えます。
cp -p /etc/tinydns/root/data /root/tinydns-data.bak
# 行の先頭の記号ごとに件数を数える
cut -c1 /etc/tinydns/root/data | sort | uniq -c
代表的な行の形式は次のとおりです。
# .ゾーン:NSのIP:NS名:TTL … NS と SOA(NS名のAも作る)
.example.lan:192.168.1.53:ns1.example.lan:3600
# =名前:IP:TTL … A と PTR
=www.example.lan:192.168.1.10:3600
# +名前:IP:TTL … A のみ
+app.example.lan:192.168.1.11:3600
# C名前:別名先:TTL … CNAME
Cwiki.example.lan:www.example.lan:3600
# @ゾーン:IP:MX名:優先度:TTL … MX(MX名のAも作る)
@example.lan:192.168.1.25:mail.example.lan:10:3600
# '名前:文字列:TTL … TXT
'example.lan:v=spf1 mx -all:3600
NS 名や MX 名にドットを含まない短い名前を書くと、TinyDNS は ns1.ns.example.lan のように独自の規則で名前を補います。書き換えのときは、tinydns-get a ns1.ns.example.lan のように TinyDNS 側で実際の名前を確かめてください。このほか、% で始まる地域別の応答、* を使ったワイルドカード、: で始まる任意の種類のレコード、IPv6 用のパッチを当てた版の独自の行などがあれば、手順2で個別に扱いを決めます。
手順2:dnsmasq の設定に書き換える
data ファイルの行は、おおむね次のように対応します。
=(A と PTR)→host-record=名前,IP(PTR も自動で作られます)+(A のみ)→host-record。逆引きも返るようになる点だけが違いますC→cname=別名,別名先@→ MX 名をhost-recordで定義したうえでmx-host=ゾーン,MX名,優先度'→txt-record=名前,"文字列"^(PTR のみ)→ptr-record=逆引き名,名前:(任意の種類)→dns-rr=名前,種類番号,16進のデータ.と&(NS・SOA・委任)→ 社内向けの用途では多くの場合不要です
dnsmasq の cname は、別名先が dnsmasq 自身の知っている名前(host-record や hosts ファイル、DHCP で登録された名前)であることが前提です。外部ドメインへの CNAME をそのまま移すと期待どおりに答えないことがあるため、手順3の比較で確認します。
設定ファイルの例です。既存のファイルと分けておくと、切り戻しが簡単になります。
# /etc/dnsmasq.d/example-lan.conf
# 上流の転送先(既存のリゾルバーのアドレスに置き換える)
no-resolv
server=192.0.2.1
domain-needed
bogus-priv
# example.lan は上流へ転送せず、ここで答える
local=/example.lan/
# 待ち受けるアドレス
listen-address=127.0.0.1,192.168.1.53
bind-interfaces
# ここで定義した名前に付ける TTL(秒)
local-ttl=300
host-record=www.example.lan,192.168.1.10
host-record=app.example.lan,192.168.1.11
host-record=ns1.example.lan,192.168.1.53
host-record=mail.example.lan,192.168.1.25
cname=wiki.example.lan,www.example.lan
mx-host=example.lan,mail.example.lan,10
txt-record=example.lan,"v=spf1 mx -all"
local=/example.lan/ を書いておくと、定義していない社内名の問い合わせが上流へ漏れず、「存在しない」とその場で答えます。また dnsmasq は、ここで定義した名前の TTL を既定では 0 にします。TinyDNS で付けていた TTL に近い値を local-ttl で指定しておかないと、利用者の端末が毎回問い合わせることになります。
% による地域別の応答は dnsmasq に直接の対応がありません(hosts ファイルの名前を、問い合わせを受けたインターフェースに合わせて返す localise-queries という近い機能はあります)。ワイルドカードは address=/example.lan/IP で「そのドメインと配下のすべての名前」に同じ IP を返す形になり、TinyDNS の * とは範囲が異なります。設定項目はバージョンで追加・変更されることがあるため、手元の man dnsmasq で確認してください(2026年10月現在)。
手順3:別ポートで起動して答えを比べる
本番の TinyDNS を動かしたまま、dnsmasq を別のポートで起動して答えを比べます。ディストリビューションのパッケージによっては、dnsmasq がインストール直後に 53 番ポートで起動して既存のサーバーとぶつかることがあるので、systemctl status dnsmasq で確認し、必要なら止めておきます。
# 構文の確認
dnsmasq --test --conf-file=/etc/dnsmasq.d/example-lan.conf
# 本番と重ならない 5300 番ポートで、前面で起動する(Ctrl+C で終了)
sudo dnsmasq --no-daemon --log-queries --port=5300 \
--conf-file=/etc/dnsmasq.d/example-lan.conf
続いて、data ファイルから名前と種類を取り出し、両方のサーバーに問い合わせて結果を並べます。
# 比較する名前と種類の一覧を作る
awk -F: '
/^[=+]/ { print substr($1, 2), "A" }
/^C/ { print substr($1, 2), "CNAME" }
/^@/ { print substr($1, 2), "MX" }
/^'\''/ { print substr($1, 2), "TXT" }
' /etc/tinydns/root/data | sort -u > names.txt
# 旧(TinyDNS)と新(dnsmasq)の答えを比べる
while read -r name type; do
old=$(dig @127.0.0.2 "$name" "$type" +short | sort | tr '\n' ' ')
new=$(dig @127.0.0.1 -p 5300 "$name" "$type" +short | sort | tr '\n' ' ')
if [ "$old" = "$new" ]; then s=OK; else s=DIFF; fi
printf '%-4s %-30s %-5s old=[%s] new=[%s]\n' "$s" "$name" "$type" "$old" "$new"
done < names.txt
DIFF が出た行は1件ずつ原因を確かめます。よくあるのは、TinyDNS が補った NS 名や MX 名の違い、CNAME の別名先が dnsmasq の知らない名前になっている場合、TXT の引用符や区切りの扱いの違いです。逆引き(dig -x 192.168.1.10)と、社外ドメインの名前解決もあわせて確認します。
手順4:切り替えと切り戻し
比較で差がなくなったら、切り替えます。作業の前に、社内の端末や DHCP が配っている DNS サーバーのアドレスを確認しておきます。dnsmasq を dnscache と同じアドレス(例では 192.168.1.53)で待ち受けさせれば、端末側の設定を変えずに済みます。そのため、dnscache を止めてから dnsmasq を起動します。
# daemontools で動かしている TinyDNS と dnscache を止める
sudo svc -d /service/tinydns
sudo svc -d /service/dnscache
# dnsmasq を通常のサービスとして起動する
sudo systemctl enable --now dnsmasq
dig @192.168.1.53 www.example.lan
dig @192.168.1.53 www.example.com
問題が出たら、sudo systemctl stop dnsmasq で止め、sudo svc -u /service/tinydns と sudo svc -u /service/dnscache で元に戻します。data ファイルと daemontools のサービス定義は、しばらく削除せずに残しておくと切り戻しに使えます。端末側のキャッシュがあるため、切り替え直後に一部の端末だけ挙動が違うことがあります。
移行でつまずきやすい点
- ポートの競合:Ubuntu などでは systemd-resolved がループバックの 53 番を使っています。
listen-addressとbind-interfacesで待ち受けを限定すると避けやすくなります。 - 外部からの問い合わせ:dnsmasq は転送も行うため、インターネットから届くアドレスで待ち受けると、誰でも使える再帰サーバーになってしまいます。ファイアウォールで社内のアドレスだけに限定してください。
- TTL の違い:
local-ttlを指定し忘れると、端末からの問い合わせ数が増えます。 - DHCP との名前の重複:dnsmasq を DHCP サーバーとしても使う場合、DHCP で登録された名前と host-record の名前がぶつからないように整理します。
まとめ
- dnsmasq への移行が向くのは、TinyDNS が社内向けの名前を答えている構成です。公開ゾーンの権威 DNS には NSD などを選びます。
- data ファイルの行は host-record・cname・mx-host・txt-record・ptr-record などに書き換えられますが、逆引きの扱いやワイルドカードの範囲が異なります。
- 別ポートで並行稼働させ、全レコードの答えを比べてから切り替えます。
- TinyDNS の設定は残しておき、問題があればすぐに戻せるようにします。