はじめに
Unbound1 をソースファイルからデプロイした際のメモをざっくりと書いていきます。もし、少しでも参考となれば嬉しいです。気付いたところがあれば都度更新予定です。
動作環境
今回は、手元のVMに Ubuntu 24.04 をインストールし、その上でUnboundをデプロイしています。
リソースは、1ソケット1コア、メモリ4GBです。
利用人数は、100人ほどを想定しています。過少に見積もっていますが、自宅で100人が使うことはないですし、もう少し設定値を上げればさらに多くの利用者を捌ける想定です。
メモリ4GBも Ubuntu の推奨要件を満たすためで、Raspberry Pi のような1GBでも安定して動作するようになっています。私は Raspberry Pi で動かしています。
構築
ディレクトリとユーザ作成
ファイルを配置するディレクトリの作成とUnboundを操作するユーザを作成します。
Docsにも以下のような記載があり、Unboundの管理するためにユーザを作成し、ログインシェルは"/usr/sbin/nologin"を指定します。
By default Unbound assumes that a user named unbound exists. You can add this user with an account management tool available on your system; on Linux this is usually useradd.
引用元:Installation — Unbound 1.24.2 documentation
### "-p"で再帰的にディレクトリを作成
$ sudo mkdir -p /var/unbound/{etc,dev,var/log,usr/local/etc/unbound,usr/local/sbin}
$ sudo groupadd unbound
$ sudo cat /etc/group
unbound:x:1001:
### "-g"で特定のグループに所属、"-d"でホームディレクトリ指定、"-s"でログインシェルを指定
$ sudo useradd -g unbound -d /var/unbound -s /usr/sbin/nologin unbound
$ sudo cat /etc/passwd
unbound:x:1001:1001::/var/unbound:/usr/sbin/nologin
パッケージをインストール
Docs2 に記載されている必要なパッケージをインストールします。
$ sudo apt install build-essential libssl-dev libevent-dev libexpat1-dev $ sudo apt-get install bison flex
ソースファイルからデプロイ
$ cd /opt $ sudo wget https://github.com/NLnetLabs/unbound/archive/refs/tags/release-1.24.2.tar.gz $ sudo tar xzf release-1.24.2.tar.gz $ cd unbound-release-1.24.2/ $ sudo ./configure --prefix=/var/unbound/usr/local \ --with-chroot-dir=/var/unbound \ --with-libevent $ sudo make $ sudo make install $ sudo /var/unbound/usr/local/sbin/unbound -V Version 1.24.2 Configure line: --prefix=/var/unbound/usr/local --with-chroot-dir=/var/unbound --with-libevent Linked libs: libevent 2.1.12-stable (it uses epoll), OpenSSL 3.0.13 30 Jan 2024 Linked modules: dns64 respip validator iterator BSD licensed, see LICENSE in source package for details. Report bugs to unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues
デバイスファイル作成とユーザと所有者の変更
$ sudo mknod -m 644 /var/unbound/dev/null c 1 3 $ sudo mknod -m 644 /var/unbound/dev/random c 1 8 $ sudo mknod -m 644 /var/unbound/dev/urandom c 1 9 $ sudo chown -R unbound:unbound /var/unbound
systemd-resolvedの停止と自動起動の無効化
既存のサービスと重複するので、"systemd-resolved"は停止します。
Docs3では、インターネットへの接続が切断されないようにファイルを書き換える方法が記載されていますが、パッケージのインストールとソースファイルのダウンロードが完了しているので、インターネットへ接続できなくても問題ありません。時刻同期に失敗することが問題の場合は、やり方を考える必要がありそうです。
事前に時刻同期先を手元で動作しているNTPサーバ宛に変更することで、インターネットへ接続できなくても時刻同期が外れることはないかもしれません。
$ lsof -i:53 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME systemd-r 567 systemd-resolve 14u IPv4 6649 0t0 UDP _localdnsstub:domain systemd-r 567 systemd-resolve 15u IPv4 6650 0t0 TCP _localdnsstub:domain (LISTEN) systemd-r 567 systemd-resolve 16u IPv4 6651 0t0 UDP _localdnsproxy:domain systemd-r 567 systemd-resolve 17u IPv4 6652 0t0 TCP _localdnsproxy:domain (LISTEN) $ sudo systemctl stop systemd-resolved $ sudo systemctl disable systemd-resolved $ systemctl status systemd-resolved <停止していることを確認> $ lsof -i:53 <出力なし>
コンフィグファイルの編集
コメントアウトで記載している内容は補足程度で記載しています。設定値は手元の環境に合わせて変更します。
$ sudo cp /var/unbound/usr/local/etc/unbound/unbound.conf /var/unbound/etc/
$ sudo vi /var/unbound/etc/unbound.conf
server:
#出力するログの詳細度
verbosity: 1
#統計情報の取得間隔(0は起動から再起動まで)
statistics-interval: 0
#累積統計を有効にする(再起動した場合は統計情報はクリアされる)
statistics-cumulative: yes
#CPUのコア数(=Socket*Core)
num-threads: 1
#問い合わせを待ち受けるIPアドレス(手元の環境に合わせて変更)
interface: 127.0.0.53
interface: <listen ip address>
#クエリを受けたIPアドレスから返す(DSRでLBを使っていたり特殊な構成の場合は"yes")
interface-automatic: no
#同時に保持できる外部への問い合わせるポート数("num-queries-per-thread"の2倍)
outgoing-range: 2048
#TCP接続数の最大値(DoT/DoHを利用する場合はもう少し多い方がいいかも)
outgoing-num-tcp: 200
incoming-num-tcp: 200
#ネットワークのバッファサイズ(パケットドロップしないようにする受け皿)
so-rcvbuf: 4m
so-sndbuf: 4m
#EDNS0で相手に伝達するUDP応答パケットサイズの最大値(1232でパケットドロップが発生する場合は1220にする)
#1232バイト=1280バイト(IPv6の最小MTU) - 40バイト(IPv6ヘッダ) - 8バイト(UDPヘッダ)
edns-buffer-size: 1232
#クライアントへのUDP返信パケットサイズの最大値(edns-buffer-sizeと同値)
max-udp-size: 1232
#問い合わせの応答内容を処理できるサイズ(これより大きなサイズは破棄)
msg-buffer-size: 65532
#問い合わせに対して回答した内容を保持するサイズ(クライアントから問い合わせにヒットするものがあればキャッシュから返答)
msg-cache-size: 64m
#"num-threads"の値に近くなる2の累乗
msg-cache-slabs: 2
#1スレッドで保持する外部問い合わせ中リクエスト数("outgoing-range"の半分)
num-queries-per-thread: 1024
#データ(レコード)を保持
rrset-cache-size: 128m
#"num-threads"の値に近くなる2の累乗
rrset-cache-slabs: 2
#問い合わせに対して回答した内容を保持する時間の最大値(低くいと頻繁に外部へ問い合わせる)
cache-max-ttl: 86400
#"num-threads"の値に近くなる2の累乗
infra-cache-slabs: 2
#外部問い合わせにダウンしていなかったり応答速度が速いなど最適なホストを保持する数
infra-cache-numhosts: 5000
do-ip4: yes
#IPv6を利用する環境であれば"yes"にする
do-ip6: no
do-udp: yes
do-tcp: yes
#外部への問い合わせを最初からTCPを利用する(FWなどでUDPがブロックされている場合は"yes")
tcp-upstream: no
#問い合わせを許可するセグメントを制限(127.0.0.53がないと自分からの名前解決ができない)
access-control: 127.0.0.53/32 allow
access-control: 192.168.1.0/24 allow
access-control: 0.0.0.0/0 refuse
#chrootのディレクトリを指定(環境に合わせて変更)
chroot: "/var/unbound"
#Unboundを管理するユーザ
username: "unbound"
#作業ディレクトリのパス(環境に合わせて変更)
directory: "/var/unbound"
#Unboundのログ格納場所(syslogを利用する場合は不要)
logfile: "/var/unbound/var/log/unbound.log"
#syslogを利用する(他のログと混在しないよう"no"にした方がいいかも)
use-syslog: no
#ログ出力にUTC-ASCIIタイムスタンプの形式を利用する(どっちでも)
log-time-ascii: yes
#ISO8601形式を利用する(どっちでも)
log-time-iso: no
#プロセスIDを記載する場所
pidfile: "/var/unbound/etc/unbound.pid"
#問い合わせの応答にバージョンや識別子を隠す(内部利用であれば気にしなくてもいいが、情報を隠す方が無難)
hide-identity: yes
hide-version: yes
#クライアントからの極端に小さかったり大きいサイズで要求する問い合わせを拒否
harden-short-bufsize: yes
harden-large-queries: yes
#権威DNSからの応答に含まれる信頼できない情報を無視(スプーフィング対策)
harden-glue: yes
#DNSSEC署名が存在すべきゾーンからの応答に署名がない場合は破棄
harden-dnssec-stripped: yes
#権威サーバからの応答で再帰的な名前解決の際に、正しい宛先であることを確認(キャッシュポイズニング対策)
#問い合わせが増えるため負荷や応答速度が少し増加し、閲覧不可となった宛先があれば、"no"にする(セキュリティ強度の上げ過ぎ)
harden-referral-path: yes
#DNSSEC検証で情弱なアルゴリズムへのダウングレートを防止
harden-algo-downgrade: yes
#最小限の情報のみ上位DNSへ問い合わせる(プライバシー保護)
qname-minimisation: yes
#問い合わせる際に、ドメイン名の大文字・小文字をランダムに入れ替えて、正しい相手からの応答であることを確認する(RFC4343 キャッシュポイズニング対策)
use-caps-for-id: yes
#有効期限が残り10%以下で問い合わせが来た場合、バックグラウンドで更新する
prefetch: yes
#有効期限が残り10%以下で問い合わせが来た場合、DNSSECの鍵情報も同様にプリフェッチする
prefetch-key: yes
#問い合わせの応答からAUTHORITY, ADDITIONALセクションを省略して返す
minimal-responses: yes
#DNSSEC検証を有効にする
module-config: "validator iterator"
#DNSSECルートトラストアンカーファイルのパス
auto-trust-anchor-file: "/var/unbound/usr/local/etc/unbound/root.key"
#DNSSEC検証結果が失敗でも結果をクライアントに返答する(キャッシュポイズニング対策)
val-permissive-mode: no
#キャッシュが切れても暫定で古いキャッシュを返す
serve-expired: no
#DNSSEC公開鍵をメモリに保持できる容量
key-cache-size: 64m
#"num-threads"の値に近くなる2の累乗
key-cache-slabs: 2
#存在しないドメインやレコードが存在しない情報をメモリに保持できる容量
neg-cache-size: 4m
#Unboundをコントローラで管理する設定(今回はローカルからの操作を想定)
remote-control:
control-enable: yes
control-interface: 127.0.0.1
control-port: 8953
server-key-file: "/var/unbound/etc/unbound_server.key"
server-cert-file: "/var/unbound/etc/unbound_server.pem"
control-key-file: "/var/unbound/etc/unbound_control.key"
control-cert-file: "/var/unbound/etc/unbound_control.pem"
forward-zone:
name: "."
#アドレスはISPから周知されているDNSやpublicのDNSを指定
forward-addr: <DNSのIPアドレス>
コントローラの証明書を作成
$ sudo /var/unbound/usr/local/sbin/unbound-control-setup -d /var/unbound/etc setup in directory /var/unbound/etc Certificate request self-signature ok subject=CN = unbound-control removing artifacts Setup success. Certificates created. Enable in unbound.conf file to use $ sudo chown -R unbound:unbound /var/unbound/etc
root.key (DNSSECルートトラストアンカー) の作成
$ sudo -u unbound /var/unbound/usr/local/sbin/unbound-anchor -a /var/unbound/usr/local/etc/unbound/root.key
confファイルの記法チェック
$ sudo /var/unbound/usr/local/sbin/unbound-checkconf /var/unbound/etc/unbound.conf unbound-checkconf: no errors in /var/unbound/etc/unbound.conf
起動と停止
### "-c"でconfファイルを指定して起動 $ sudo /var/unbound/usr/local/sbin/unbound -c /var/unbound/etc/unbound.conf $ sudo /var/unbound/usr/local/sbin/unbound-control -c /var/unbound/etc/unbound.conf status version: 1.24.2 verbosity: 1 threads: 1 modules: 2 [ validator iterator ] uptime: 17 seconds options: reuseport control(ssl) unbound (pid 10261) is running... ### "-c"でconfファイルを指定して停止 $ sudo /var/unbound/usr/local/sbin/unbound-control -c /var/unbound/etc/unbound.conf stop ok ### エラーは unbound-control で操作するための 127.0.0.1:8953 へ接続できないためで、停止しているので接続できないのは問題なし $ sudo /var/unbound/usr/local/sbin/unbound-control -c /var/unbound/etc/unbound.conf status [1772258159] unbound-control[10292:0] error: connect: Connection refused for 127.0.0.1 port 8953 unbound is stopped
systemdの設定
ファイルの作成
systemdで起動する際のシェルスクリプトとサービスファイルを作成します。
$ sudo tee /var/unbound/usr/local/sbin/unbound_start.sh <<EOF #!/bin/sh /var/unbound/usr/local/sbin/unbound -c /var/unbound/etc/unbound.conf -d EOF $ sudo chmod +x /var/unbound/usr/local/sbin/unbound_start.sh $ sudo chown unbound:unbound /var/unbound/usr/local/sbin/unbound_start.sh ### 内容が多いのでviコマンドなどで作成しても可 $ sudo tee /etc/systemd/system/unbound-chroot.service <<EOF [Unit] Description=Unbound DNS Server in chroot After=network.target [Service] Type=simple User=unbound Group=unbound DynamicUser=no NoNewPrivileges=true SupplementaryGroups= ExecStartPre=/var/unbound/usr/local/sbin/unbound-checkconf /var/unbound/etc/unbound.conf ExecStart=/var/unbound/usr/local/sbin/unbound_start.sh ExecStop=/var/unbound/usr/local/sbin/unbound-control -c /var/unbound/etc/unbound.conf stop Restart=always CapabilityBoundingSet=CAP_SETGID CAP_SETUID CAP_NET_BIND_SERVICE CAP_SYS_CHROOT AmbientCapabilities=CAP_SETGID CAP_SETUID CAP_NET_BIND_SERVICE CAP_SYS_CHROOT [Install] WantedBy=multi-user.target EOF
ネットワークバッファ制限値の変更
今回の想定している利用規模では、変更する必要はありませんが、Unboundの起動時に警告が出るため変更しています。出力される警告は動作に影響はありませんので、気にならない方や余計な設定変更はしたくない場合、変更は不要です。
規模が大きい場合は変更し、さらに大きい場合は、"8388608(8MB)"またはそれ以上にすることを検討します。
$ sudo vi /etc/sysctl.conf + net.core.rmem_max = 4194304 + net.core.wmem_max = 4194304 $ sudo sysctl -p net.core.rmem_max = 4194304 net.core.wmem_max = 4194304
起動
$ sudo systemctl daemon-reload
$ sudo systemctl enable unbound-chroot.service
$ sudo systemctl start unbound-chroot.service
$ sudo systemctl status unbound-chroot.service
● unbound-chroot.service - Unbound DNS Server in chroot
Loaded: loaded (/etc/systemd/system/unbound-chroot.service; enabled; preset: enabled)
Active: active (running) since Sat 2026-02-28 06:29:56 UTC; 12min ago
Process: 10761 ExecStartPre=/var/unbound/usr/local/sbin/unbound-checkconf /var/unbound/etc/unbound.conf (code=exited, status=0/SUCCESS)
Main PID: 10763 (unbound_start.s)
Tasks: 2 (limit: 4603)
Memory: 87.7M (peak: 87.9M)
CPU: 1.165s
CGroup: /system.slice/unbound-chroot.service
tq10763 /bin/sh /var/unbound/usr/local/sbin/unbound_start.sh
mq10764 /var/unbound/usr/local/sbin/unbound -c /var/unbound/etc/unbound.conf -d
Feb 28 06:29:56 <hostname> systemd[1]: Starting unbound-chroot.service - Unbound DNS Server in chroot...
Feb 28 06:29:56 <hostname> unbound-checkconf[10761]: unbound-checkconf: no errors in /var/unbound/etc/unbound.conf
Feb 28 06:29:56 <hostname> systemd[1]: Started unbound-chroot.service - Unbound DNS Server in chroot.
### ログで起動を確認
$ sudo tail /var/unbound/var/log/unbound.log
Feb 28 06:29:56 unbound[10664:0] notice: init module 0: validator
Feb 28 06:29:56 unbound[10664:0] notice: init module 1: iterator
Feb 28 06:29:56 unbound[10664:0] info: start of service (unbound 1.24.2).
状態確認
プロセス確認
systemdで起動するようにした際に、起動スクリプトにバックグラウンドで起動するように記載したので、起動シェルスクリプトとバックグラウンド起動の二つが出力されます。
$ ps aux | grep unbound unbound 15985 0.0 0.0 2328 832 ? Ss Feb28 0:00 /bin/sh /var/unbound/usr/local/sbin/unbound_start.sh unbound 15986 0.0 2.8 11032 19300 ? S Feb28 0:50 /var/unbound/usr/local/sbin/unbound -c /var/unbound/etc/unbound.conf -d
chroot確認
PIDは、確認した起動プロセスを指定します。 chrootで指定したディレクトリが表示されることを確認する。
$ sudo ls -l /proc/<PID>/root lrwxrwxrwx 1 unbound unbound 0 Feb 28 06:51 /proc/15986/root -> /var/unbound
DNSSEC動作確認
失敗する場合は、以下のような結果となります。"status"が「SERVFAIL」となります。
最初の数回ほどタイムアウトする原因はわかりません。単純に時間がかかっているのかも。
$ sudo dig @127.0.0.53 +dnssec sigfail.verteiltesysteme.net ;; communications error to 127.0.0.53#53: timed out ; <<>> DiG 9.18.39-0ubuntu0.24.04.2-Ubuntu <<>> @127.0.0.53 +dnssec sigfail.verteiltesysteme.net ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 32565 ;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags: do; udp: 1232 ;; QUESTION SECTION: ;sigfail.verteiltesysteme.net. IN A ;; Query time: 0 msec ;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP) ;; WHEN: Sat Feb 28 06:10:40 UTC 2026 ;; MSG SIZE rcvd: 57
成功する場合は、失敗の際と異なり、"status"が「NOERROR」となります。
また、"flags"に「ad」が表示され、"ANSWER SECTION"にはRRSIGレコードが返されます。
$ sudo dig @127.0.0.53 +dnssec sigok.verteiltesysteme.net ;; communications error to 127.0.0.53#53: timed out ; <<>> DiG 9.18.39-0ubuntu0.24.04.2-Ubuntu <<>> @127.0.0.53 +dnssec sigok.verteiltesysteme.net ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 47080 ;; flags: qr rd ra ad; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags: do; udp: 1232 ;; QUESTION SECTION: ;sigok.verteiltesysteme.net. IN A ;; ANSWER SECTION: sigok.verteiltesysteme.net. 1795 IN CNAME sigok.rsa2048-sha256.ippacket.stream. sigok.verteiltesysteme.net. 1795 IN RRSIG CNAME 13 3 1799 202603001000000 20260210000000 46187 verteiltesysteme.net. ********************************** sigok.rsa2048-sha256.ippacket.stream. 59 IN A 123.234.56.36 sigok.rsa2048-sha256.ippacket.stream. 59 IN RRSIG A 8 4 60 202603001040000 20260131040002 46460 rsa2048-sha256.ippacket.stream. ************************************ ;; Query time: 245 msec ;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP) ;; WHEN: Sat Feb 28 06:10:24 UTC 2026 ;; MSG SIZE rcvd: 555
性能確認
以下のコマンドを実行し、統計情報を出力します。
$ sudo /var/unbound/usr/local/sbin/unbound-control -c /var/unbound/etc/unbound.conf stats_noreset
unbound.confで設定した制限に抵触した通信が増えている場合は、起動直後であれば何らかの不具合が生じていると見るべきです。
total.num.queries_ip_ratelimited=0 #攻撃(怪しい問い合わせ)対策に抵触した問い合わせの数
どの程度のキャッシュがヒットしているかなどを確認できます。
問い合わせ数:728(total.num.queries) = 404(total.num.cachehits) + 324(total.num.cachemiss)
キャッシュヒット率:404(total.num.cachehits) / 728(total.num.queries) * 100 = 55%
外部への問い合わせ数:324(total.num.cachemiss) = 322(total.num.recursivereplies) + 2(total.num.queries_discard_timeout)
total.num.queries=728 #DNSに来た問い合わせの総数 total.num.cachehits=404 #キャッシュにヒットした数 total.num.cachemiss=324 #キャッシュにヒットしなかった数(=外部への問い合わせた数) total.num.recursivereplies=322 #外部への問い合わせからの応答数 total.num.queries_discard_timeout=2 #タイムアウトにより破棄された問い合わせの数
"total.requestlist.max"は"num-queries-per-thread"で指定した値の1/3までは安全、半分を超えると注意が必要かも。
total.requestlist.max=13 #同時処理した最大問い合わせの数 total.requestlist.overwritten=0 #処理しきれずに破棄した問い合わせの数 total.requestlist.exceeded=0 #処理しきれずに破棄した問い合わせの数
平均値が中央値の10倍を超えると一部の問い合わせに時間がかかっているかタイムアウトの可能性があるので、"forward-addr"の宛先DNSを変更してみたり、"serve-expired"を"yes"にしてみる。動作と体感に大きな問題がなければ無視してもいいと思います。
total.recursion.time.avg=0.021824 #キャッシュにヒットせず外部への問い合わせからの応答速度の平均値(s) total.recursion.time.median=0.0064 #キャッシュにヒットせず外部への問い合わせからの応答速度の中央値(s)

















