Raspberry PiとUnboundによるDNSキャッシュサーバの構築

DNSキャッシュサーバをLAN内部に作成し、クライアントが問い合わせるDNSサーバをGoogle Public DNSなどのPublic DNSからこちらに変更することで、次の効果により名前解決を高速化し、Webブラウジング等をより快適にすることを目指す。

  • 自分専用のDNSキャッシュサーバを用意することで、キャッシュヒット率を上げる
  • なるべくLAN内部で名前解決が完結するようにし、インターネット越しに名前解決することによる、距離的な時間のロスを減らす

Unboundを用いてDNSキャッシュサーバを構築する。また、上記目的を踏まえ、クライアントからの問い合わせを受けてルートドメインから反復問い合わせするフルサービスリゾルバを構築するのではなく、キャッシュヒットしなかった問い合わせを別のフルサービスリゾルバ (Google Public DNSなど)に中継するフォワーダとして構築する。

Raspberry Piのセットアップ

Raspberry Pi本体をどこかしらから調達する。最近のRaspberry Piであれば64bit CPUが搭載されているので、導入するRaspberry Pi OSを選ぶ際、可能であれば64bit OSを選ぶ。また、サーバ用途で利用する場合、GUIは不要なので、Liteバージョンを選ぶとハードウェア資源を有効活用できる。

Raspberry Pi自体のセットアップは割愛する。TimeZoneの設定などを忘れずに。

ネットワークにWi-Fi経由で接続できるモデルもあるが、接続の安定性・通信速度の観点からなるべくEthernet(有線接続)経由でネットワークに接続させることが望ましい。加えて、サーバ用途であるため、IPアドレスも固定させておく必要がある。大抵の場合、LANを構築するルータがDHCPサーバを兼ねており、クライアントに対してプライベートIPアドレスが自動的に払い出される状態になっていると思う。その場合は、 /etc/dhcpcd.conf を編集し、DHCPクライアントの設定により固定のIPアドレスを用いるよう対応する。設定ファイル中に設定例が豊富にコメントされているので、それらを見てもらえれば理解できると思うが、Debian WikiArchWikiも参考になる。

interface eth0
static ip_address=192.168.1.3/24
static routers=192.168.1.1
static domain_name_servers=8.8.8.8 8.8.4.4

domain_name_servers については、UnboundによるDNSキャッシュサーバを構築後、そちらを指すように変更するが、ひとまず現状はGoogle Public DNSを指定しておく。

ルータの設定でも、Raspberry Piに対し上記指定したIPアドレスを固定で払い出すよう、設定しておく。

Unboundの導入

Raspberry Piがインターネットに疎通したら、Unboundを導入する。Raspberry Pi OSはDebianベースなので、apt-getでインストール。

# apt-get install unbound

導入できたら、 /etc/unbound/unbound.conf に対して設定を加えていく。設定のドキュメントは /usr/share/doc/unbound/examples/unbound.conf にあるので、そちらを参照すること。僕自身は、以下のように設定した。

# Unbound configuration file for Debian.
#
# See the unbound.conf(5) man page.
#
# See /usr/share/doc/unbound/examples/unbound.conf for a commented
# reference config file.
#
# The following line includes additional configuration files from the
# /etc/unbound/unbound.conf.d directory.
include-toplevel: "/etc/unbound/unbound.conf.d/*.conf"

server:
	verbosity: 0 # エラー以外はログに出さない
	num-threads: 4 # CPUコア数と同数にする
	interface: 0.0.0.0 # 接続を受け付けるIPアドレスは制限しない
	outgoing-range: 206 # 1024/cores - 50
	num-queries-per-thread: 103 # outgoing-range / 2
	so-reuseport: yes
	msg-cache-size: 512m # キャッシュサイズはお好みで
	msg-cache-slabs: 4 # slabs系は、num-threadsに近しい2の累乗にする
	rrset-cache-size: 1g # msg-cache-sizeの2倍にする
	rrset-cache-slabs: 4 # slabs系は、num-threadsに近しい2の累乗にする
	infra-cache-slabs: 4 # slabs系は、num-threadsに近しい2の累乗にする
	do-ip4: yes
	do-ip6: no # 契約しているISPがIPv6アドレスも払い出しているなら、yesにする
	do-udp: yes
	do-tcp: yes
	access-control: 0.0.0.0/0 refuse # Allow Listにしたいので、まずは全て拒否
	access-control: 127.0.0.0/8 allow # 自分自身からのアクセスを許可する
	access-control: 192.168.1.0/24 allow # LANに属するクライアントからのアクセスを許可する
    # フルサービスリゾルバとしてUnboundを構築したいなら、ArchWiki等を参考にInterNICからnamed.cacheを取得し、Root hintsとして設定する
	# root-hints: root.hints 
	hide-identity: yes
	hide-version: yes
	cache-min-ttl: 3600
	prefetch: yes
	key-cache-size: 512m # キャッシュサイズはお好みで
	key-cache-slabs: 4 # slabs系は、num-threadsに近しい2の累乗にする
	neg-cache-size: 512m # キャッシュサイズはお好みで
	minimal-responses: yes
	rrset-roundrobin: yes
    # DNSで特定ドメインをNXDOMAINにしブロックしたいなら、Unbound用(local-zone:で定義されているもの)を拾ってきて、以下のように定義する
    # https://github.com/openwrt/packages/tree/master/net/adblock/files あたりから探すと良い
	# include: /etc/unbound/adblock-rules.conf
forward-zone:
	# キャッシュにヒットしなかったら、Google Public DNSに問い合わせをフォワードする
	name: "."
	forward-addr: 8.8.8.8
	forward-addr: 8.8.4.4

パフォーマンスチューニングに際しては、次の記事が参考になる。

Performance Tuning — Unbound 1.14.0 documentation
DNSキャッシュサーバ チューニングの勘所
BIND9部分を公開しました。いくつか加筆修正しVer1.1になりました。

以上でUnboundの設定が完了となる。以下コマンドにより、設定ファイルの記載内容に誤りがないかを確認する。

$ unbound-checkconf /etc/unbound/unbound.conf

no errors in... のように返ってきたら問題ない。エラーが返されたら、内容を確認して、typoがないか等を調べる。

設定に問題が無いようなら、以下でUnboundを立ち上げる。

# service unbound start

正常に起動したかを以下で調べる。

$ service unbound status

以下コマンドにより実際に名前解決の問い合わせをUnboundに投げて、名前解決されるかを確認する。

$ dig www.google.com @192.168.1.3

上記は、同一LANに属するクライアントから問い合わせを投げる例。Raspberry Pi内部で動作確認する際は、 @127.0.0.1 とする。

Unboundを用いるよう設定

正常に名前解決できることが確認できたら、このUnboundをDNSサーバとして用いるよう、各クライアントで設定する。

クライアントで設定する前に、Raspberry Pi自身が用いるDNSサーバとして、このUnboundを用いるよう設定する。本記事冒頭でdhcpcdの設定をした際、 domain_name_servers にGoogle Public DNSを指定したが、これをUnboundに変更する。

# /etc/dhcpcd.conf

static domain_name_servers=127.0.0.1

次に、各クライアントのネットワーク設定で、DNSサーバとしてUnboundを用いるよう設定変更する。個別にRaspberry PiのIPアドレスを指定しても良いが、ルータのDHCPサーバ設定からDNSサーバアドレスを指定する形にしても良い。


以上で、対応完了となる。初めてアクセスするドメインの場合は、問い合わせをフォワードする都合上、今までと名前解決に要する時間は変わらない。だが、問い合わせ結果がキャッシュされてからは、ドメインのTTL(キャッシュの有効期限)以内であれば、LAN内部でより迅速に名前解決できる。

参考

Install Raspberry Pi OS Bullseye on Raspberry Pi (Illustrated guide) | Raspberry tips
Raspberry Pi OS is the official operating system for a Raspberry Pi. Most kits include it by default, but when you need to reinstall it,…
DHCP_Client - Debian Wiki
dhcpcd - ArchWiki
Unbound - ArchWiki
Performance Tuning — Unbound 1.14.0 documentation
DNSキャッシュサーバ チューニングの勘所
BIND9部分を公開しました。いくつか加筆修正しVer1.1になりました。
packages/net/adblock/files at master · openwrt/packages
Community maintained packages for OpenWrt. Documentation for submitting pull requests is in CONTRIBUTING.md - packages/net/adblock/files at master · openwrt/packages