内部ネットワーク向けDNSサーバーの3つの選択肢
約半年間、約50台のサーバーが稼働する本番環境で内部DNSシステムを運用してきました。BIND9に落ち着く前に3つの異なるソリューションを試した経験から、実際の現場で得た知見をまとめます。
CentOS Stream 9での内部DNSサーバーとして最も一般的な3つの選択肢:
- BIND9 (Berkeley Internet Name Domain) — 最も機能が豊富な従来型DNSソリューション
- dnsmasq — 軽量で設定が簡単、小規模ネットワーク向け
- Unbound — 再帰的DNSに特化し、セキュリティが高いが権威DNS機能は限定的
各ソリューションのメリット・デメリット分析
dnsmasq — シンプルだが制限あり
設定が15分で完了するため、最初はdnsmasqから始めました。しかしホスト数が増え、複数のゾーン(lab.company.local、db.company.localなど)を管理する必要が生じると、dnsmasqの弱点が露わになってきました。実際のゾーンファイルがなく、プライマリとセカンダリDNS間の同期に必要なAXFRも非対応です。また、ログが少ないため障害発生時のデバッグも非常に不便でした。
適しているケース: 個人ラボ、家庭ネットワーク、20台以下のホスト、プライマリ・セカンダリ間のレプリケーションが不要な場合。
Unbound — セキュリティは高いが権威DNS機能が不足
Unboundは再帰的DNS(インターネットへのクエリ転送)に非常に優れています。しかし、権威DNSサーバー(自社ネットワーク内の内部ホスト名を解決するサーバー)としては設計されていません。server01.company.localの名前解決にUnboundを使うのは適切なユースケースではなく、複雑な回避策が必要になります。
適しているケース: 再帰的リゾルバーのみが必要で、DNSSECバリデーションによるセキュリティを優先する場合。
BIND9 — 複雑だが価値あり
最終的にBIND9を選択しました。設定は複雑ですが、その分ゾーンファイルが明確で、フォワードとリバースルックアップの両方に対応し、プライマリ・セカンダリ間のレプリケーション設定も可能で、公式ドキュメントも充実しています。SELinux enforcingのCentOS Stream 9では、BIND9の方がより徹底的にテストされており、namedのSELinuxポリシーがシステムにあらかじめ定義されています。
適しているケース: 企業ネットワーク、複数ゾーンの管理、権威DNSが必要な場合、高可用性のためのプライマリ・セカンダリ構成が必要な場合。
BIND9を選んだ実際の理由
弊社にはまだCentOS 7で動いているサーバーが数台あり、AlmaLinuxへの移行は実際に取り組んだ課題でした。移行期間中、旧環境と新環境の両方を並行して扱える強力なDNSサーバーが必要でした。複数のゾーンを個別に設定できるBIND9が最も自然な選択です。さらに、インフラ全体がSELinux enforcing(CentOS Stream 9のデフォルト)で動いている環境では、ファイルを正しい場所に配置さえすれば、BIND9はほとんど問題を起こしません。
CentOS Stream 9へのBIND9の導入
ステップ1:パッケージのインストール
sudo dnf install -y bind bind-utils
sudo systemctl enable --now named
sudo systemctl status named
ステップ2:named.confの設定
メインの設定ファイルは/etc/named.confです。内部ゾーンcompany.localの権威DNSとしてBIND9を設定し、残りのクエリはパブリックDNSに転送するように構成します:
sudo nano /etc/named.conf
options {
listen-on port 53 { 127.0.0.1; 192.168.1.10; }; # DNSサーバーのIPアドレス
listen-on-v6 port 53 { none; };
directory "/var/named";
dump-file "/var/named/data/cache_dump.db";
statistics-file "/var/named/data/named_stats.txt";
allow-query { localhost; 192.168.1.0/24; }; # 内部サブネットのみ許可
# DNSクエリを外部インターネットに転送
forwarders {
8.8.8.8;
8.8.4.4;
};
forward only;
recursion yes;
dnssec-validation yes;
};
logging {
channel default_debug {
file "data/named.run";
severity dynamic;
};
};
# 内部ゾーン(フォワード)
zone "company.local" IN {
type master;
file "company.local.zone";
allow-update { none; };
};
# 192.168.1.0/24サブネットのリバースゾーン
zone "1.168.192.in-addr.arpa" IN {
type master;
file "company.local.rev";
allow-update { none; };
};
include "/etc/named.rfc1912.zones";
include "/etc/named.root.key";
ステップ3:フォワードゾーンファイルの作成
sudo nano /var/named/company.local.zone
$TTL 86400
@ IN SOA ns1.company.local. admin.company.local. (
2024010101 ; シリアル番号(YYYYMMDDNN形式 — 変更のたびに増やす)
3600 ; Refresh
1800 ; Retry
604800 ; Expire
86400 ) ; 最小TTL
; ネームサーバー
@ IN NS ns1.company.local.
; Aレコード
ns1 IN A 192.168.1.10
gateway IN A 192.168.1.1
server01 IN A 192.168.1.20
server02 IN A 192.168.1.21
db01 IN A 192.168.1.30
webserver IN A 192.168.1.40
; CNAME
www IN CNAME webserver.company.local.
シリアル番号はよく見落とされる重要なポイントです:ゾーンファイルを変更するたびに必ず増やす必要があります。BIND9はこの値を使ってゾーンをリロードするかどうかを判断します。
ステップ4:リバースゾーンファイルの作成
sudo nano /var/named/company.local.rev
$TTL 86400
@ IN SOA ns1.company.local. admin.company.local. (
2024010101
3600
1800
604800
86400 )
@ IN NS ns1.company.local.
; PTRレコード(逆引き)
10 IN PTR ns1.company.local.
1 IN PTR gateway.company.local.
20 IN PTR server01.company.local.
21 IN PTR server02.company.local.
30 IN PTR db01.company.local.
40 IN PTR webserver.company.local.
ステップ5:再起動前の構文チェック
# named.confの構文チェック
sudo named-checkconf
# フォワードゾーンの確認
sudo named-checkzone company.local /var/named/company.local.zone
# リバースゾーンの確認
sudo named-checkzone 1.168.192.in-addr.arpa /var/named/company.local.rev
# エラーがなければ再起動
sudo systemctl restart named
SELinuxの対処 — 最も見落とされがちな部分
初回セットアップで最も時間を費やした部分です。SELinux enforcingは、ゾーンファイルのコンテキストが正しくない場合にBIND9をブロックします。ゾーンファイルは必ず/var/named/内に配置する必要があります — /etc/や独自に作成したディレクトリには置かないでください。
ゾーンファイルのSELinuxコンテキストを確認:
ls -lZ /var/named/company.local.zone
正しい出力にはnamed_zone_tが含まれている必要があります:
-rw-r--r--. 1 root named system_u:object_r:named_zone_t:s0 /var/named/company.local.zone
コンテキストが間違っている場合(例:別の場所からファイルをコピーした場合)は、以下のコマンドで修正します:
sudo restorecon -Rv /var/named/
sudo chown root:named /var/named/company.local.zone /var/named/company.local.rev
SELinuxがnamedをブロックしているか確認:
sudo ausearch -c 'named' -m avc --raw 2>/dev/null | head -20
sudo tail -f /var/log/audit/audit.log | grep named
firewalldの設定
内部サブネット向けにDNSポート(53/udpおよび53/tcp)を開放します:
# 方法1:DNSサービスを全体に開放
sudo firewall-cmd --permanent --add-service=dns
sudo firewall-cmd --reload
# 方法2:内部サブネットからのみ許可(推奨)
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" service name="dns" accept'
sudo firewall-cmd --reload
# 確認
sudo firewall-cmd --list-all
DNSサーバーのテスト
# フォワードルックアップのテスト
dig @192.168.1.10 server01.company.local
# リバースルックアップのテスト
dig @192.168.1.10 -x 192.168.1.20
# インターネットへのフォワードDNSテスト
dig @192.168.1.10 google.com
# 内部ネットワーク上のクライアントから
nslookup server01.company.local 192.168.1.10
NetworkManagerを使用してクライアントのDNS設定を更新:
sudo nmcli con mod "Wired connection 1" ipv4.dns "192.168.1.10"
sudo nmcli con mod "Wired connection 1" ipv4.dns-search "company.local"
sudo nmcli con up "Wired connection 1"
よくあるエラーとその対処法
- namedが起動しない: まずSELinuxコンテキストを確認し、その後
journalctl -u named -n 50を実行 - クライアントからのクエリタイムアウト: 99%はfirewalldがポートを開放していない —
firewall-cmd --list-all | grep dnsで確認 - ゾーンファイルがリロードされない: シリアル番号が増加していない — シリアルを変更してから
sudo rndc reload company.localを実行 - ログにPermission denied: ゾーンファイルのグループがnamedになっていない —
chown root:named /var/named/*.zoneで修正
次のステップ
このセットアップは本番環境で6ヶ月間安定稼働しています。最も難しい部分は実際には最初だけ — 特にSELinuxコンテキストとfirewalldの設定です。一度BIND9が正常に動き出せば、ほとんど手を加える必要はありません。
さらに高度な構成を目指すなら、次のステップはtype slaveとAXFRレプリケーションを使ったセカンダリDNSサーバーの構築です。プライマリDNSに障害が発生しても、内部ネットワークが引き続き正常に名前解決できるようになります。
