0. DNSとは
DNS(Domain Name System)とは,ドメイン名とIPアドレスなどの情報の紐付けをするための仕組みのことです。コンピューターはドメイン名同士でインターネット通信しているのではなくドメイン名をIPアドレスに変換して通信をしています。コンピューターは2進法を使いますが,人間には分かりづらいのでIPv4は10進法で,IPv6は16進法で表記しているわけですが,いちいちIPアドレスを覚えていられないですね。そのためのDNSです。DNSという画期的なシステムがドメインとIPアドレスの紐付けをしてくれることで人間にとってとても分かりやすいドメイン名での通信ができるわけです。今回はこのDNSサーバーを建ててみようというお話です。
1. DNSレコードについて
DNSレコードとは,特定のドメインにおけるIPアドレスなどの情報を記録したデータです。例えばIPv4アドレスを記録するDNSレコードはAレコードになります。他にもAAAAレコードや,CNAMEレコード,TXT,DS,DNSKEY,HTTPSなど様々なレコードがあります。
・Aレコードについて
IPv4アドレスを記録しているDNSレコードです。DNSサーバーにAレコードを登録する時は,IPv4アドレスのみが指定できます。digコマンドでqiita.comのIPv4アドレスを調べてみましょう。
$ dig qiita.com. a
; <<>> DiG 9.20.17 <<>> qiita.com. A
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 49356
;; flags: qr rd ra; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;qiita.com. IN A
;; ANSWER SECTION:
qiita.com. 37 IN A 18.65.207.34
qiita.com. 37 IN A 18.65.207.93
qiita.com. 37 IN A 18.65.207.4
qiita.com. 37 IN A 18.65.207.100
;; Query time: 16 msec
;; SERVER: 1.1.1.1#53(1.1.1.1) (UDP)
;; WHEN: Thu Dec 25 09:17:28 JST 2025
;; MSG SIZE rcvd: 102
このようにANSWER SECTION:にAレコードに割当されたIPv4アドレスが分かります。18.65.207.0/24から4つほどIPv4アドレスの割り当てをしているようです。
・AAAAレコードについて
AAAAレコードはIPv6アドレスを記録するDNSレコードです。AAAAレコードを登録する際はIPv6アドレスのみ登録できます。では,先ほどと同じようにdigでqiita.comのAAAAレコードを調べてみましょう。
$ dig qiita.com. aaaa
; <<>> DiG 9.20.17 <<>> qiita.com. AAAA
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 59496
;; flags: qr rd ra; QUERY: 1, ANSWER: 8, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;qiita.com. IN AAAA
;; ANSWER SECTION:
qiita.com. 38 IN AAAA 2600:9000:221b:1c00:8:e1de:4d80:93a1
qiita.com. 38 IN AAAA 2600:9000:221b:4000:8:e1de:4d80:93a1
qiita.com. 38 IN AAAA 2600:9000:221b:ba00:8:e1de:4d80:93a1
qiita.com. 38 IN AAAA 2600:9000:221b:e400:8:e1de:4d80:93a1
qiita.com. 38 IN AAAA 2600:9000:221b:7800:8:e1de:4d80:93a1
qiita.com. 38 IN AAAA 2600:9000:221b:ea00:8:e1de:4d80:93a1
qiita.com. 38 IN AAAA 2600:9000:221b:9c00:8:e1de:4d80:93a1
qiita.com. 38 IN AAAA 2600:9000:221b:ae00:8:e1de:4d80:93a1
;; Query time: 12 msec
;; SERVER: 1.1.1.1#53(1.1.1.1) (UDP)
;; WHEN: Thu Dec 25 09:23:16 JST 2025
;; MSG SIZE rcvd: 262
このように表示されます。IPv6アドレスは128bitもあり,大量に有り余っているので,qiita.comには8個のIPv6アドレスの割り当てがされているようです。割り当てしているIPv6アドレスは前から49~64bit目の部分を変えているようですね。
・NSレコードについて
NSレコードは,ネームサーバーを記録するDNSレコードです。NSレコードを調べることでそのドメインの権威DNSサーバーを調べることができます。
では権威DNSサーバーを調べてみましょう。
$ dig qiita.com. ns
; <<>> DiG 9.20.17 <<>> qiita.com. NS
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 16842
;; flags: qr rd ra; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;qiita.com. IN NS
;; ANSWER SECTION:
qiita.com. 300 IN NS ns-1049.awsdns-03.org.
qiita.com. 300 IN NS ns-171.awsdns-21.com.
qiita.com. 300 IN NS ns-1956.awsdns-52.co.uk.
qiita.com. 300 IN NS ns-772.awsdns-32.net.
;; Query time: 108 msec
;; SERVER: 1.1.1.1#53(1.1.1.1) (UDP)
;; WHEN: Thu Dec 25 09:34:54 JST 2025
;; MSG SIZE rcvd: 175
複数のネームサーバーが割当てされています。ネームサーバーは原則最低2つ割当てしなければなりません。TLDとセカンドレベルドメインから判別すると1つはイギリスにあるネームサーバーを使用しているようです。ドメイン名にAWSが含まれているのでRoute53を使っていると予想ができます。では,このいずれかのドメインを利用してqiita.com.に割当てされているA,AAAAレコードを調べてみましょう。
# Aレコードの確認
$ dig qiita.com. a @ns-1049.awsdns-03.org
; <<>> DiG 9.20.17 <<>> @ns-1049.awsdns-03.org qiita.com. a
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 4353
;; flags: qr aa rd; QUERY: 1, ANSWER: 4, AUTHORITY: 4, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;qiita.com. IN A
;; ANSWER SECTION:
qiita.com. 60 IN A 18.65.207.34
qiita.com. 60 IN A 18.65.207.93
qiita.com. 60 IN A 18.65.207.100
qiita.com. 60 IN A 18.65.207.4
;; AUTHORITY SECTION:
qiita.com. 300 IN NS ns-1049.awsdns-03.org.
qiita.com. 300 IN NS ns-171.awsdns-21.com.
qiita.com. 300 IN NS ns-1956.awsdns-52.co.uk.
qiita.com. 300 IN NS ns-772.awsdns-32.net.
;; Query time: 12 msec
;; SERVER: 2600:9000:5304:1900::1#53(ns-1049.awsdns-03.org) (UDP)
;; WHEN: Thu Dec 25 09:38:48 JST 2025
;; MSG SIZE rcvd: 239
# AAAAレコードの確認
$ dig qiita.com. aaaa @ns-1049.awsdns-03.org
; <<>> DiG 9.20.17 <<>> @ns-1049.awsdns-03.org qiita.com. aaaa
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 5815
;; flags: qr aa rd; QUERY: 1, ANSWER: 8, AUTHORITY: 4, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;qiita.com. IN AAAA
;; ANSWER SECTION:
qiita.com. 60 IN AAAA 2600:9000:221b:200:8:e1de:4d80:93a1
qiita.com. 60 IN AAAA 2600:9000:221b:1200:8:e1de:4d80:93a1
qiita.com. 60 IN AAAA 2600:9000:221b:8600:8:e1de:4d80:93a1
qiita.com. 60 IN AAAA 2600:9000:221b:a400:8:e1de:4d80:93a1
qiita.com. 60 IN AAAA 2600:9000:221b:7a00:8:e1de:4d80:93a1
qiita.com. 60 IN AAAA 2600:9000:221b:2e00:8:e1de:4d80:93a1
qiita.com. 60 IN AAAA 2600:9000:221b:b400:8:e1de:4d80:93a1
qiita.com. 60 IN AAAA 2600:9000:221b:a000:8:e1de:4d80:93a1
;; AUTHORITY SECTION:
qiita.com. 300 IN NS ns-1049.awsdns-03.org.
qiita.com. 300 IN NS ns-171.awsdns-21.com.
qiita.com. 300 IN NS ns-1956.awsdns-52.co.uk.
qiita.com. 300 IN NS ns-772.awsdns-32.net.
;; Query time: 18 msec
;; SERVER: 2600:9000:5304:1900::1#53(ns-1049.awsdns-03.org) (UDP)
;; WHEN: Thu Dec 25 09:39:03 JST 2025
;; MSG SIZE rcvd: 399
ちゃんと1.1.1.1(Cloudflare DNS)と権威サーバーによるAレコードは同じですね。AAAAレコードは実際にもっとたくさん割当てされており一致はしませんでしたが,やはり49~64bitの部分以外は一緒なので表示されるIPv6アドレスは変わらないと言っても差し支えないでしょう。
2. DNSサーバーを構築するにあたって
DNSサーバーを構築するためにはDNSサーバーを構築するためのソフトウェアが必要です。今回はISC BIND9を使用します。結構昔から使われているDNSサーバーだと思います。digコマンドがBINDのツールですね。最近はnet-toolsからdig,iproute2への移行が推奨されているようです。今回はUbuntuでやりますが,他のディストリビューションでも同じようにできると思います。RHEL系のセキュリティ機能の強化で使用されるSELinuxについてはBIND9にどのような影響を与えるのかがまだ確かめたことがないので時間がある時にテストしてみます。
3. BIND9をインストール
まずはインストールしないと始まりません。インストールをしていきましょう。
$ sudo apt-get install bind9 bind9-utils bind9utils
パッケージのインストールができたら設定を始めていきます。Linuxはデフォルトで使用されるリゾルバーがsystemd-resolvedパッケージによって設定されているので,BIND9を起動するのに邪魔なこのパッケージを削除します。
$ sudo apt-get purge systemd-resolved -y
設定を始めていきます。内部ネットワーク向けと外部ネットワーク向けでやり方が変わります。最初にまずは内部ネットワーク向けの設定からやってみましょう。
4.内部ネットワーク向け(リゾルバーの構築)
内部ネットワーク向けに構築するのでポート開放の必要はありません。ソフトウェアファイアウォールで内部ネットワーク向けに53/TCP,53/UDPを開放するだけでOKです。
ファイルの編集をしていきます。/etc/bind/内のnamed.conf.localはゾーンファイルの記入,named.conf.optionsはBIND9の挙動の指定を設定するファイルです。内部ネットワーク向けなのでnamed.conf.optionsだけ編集しておけばいいと思います。では編集していきましょう。
//ACLを追記
acl local-network { 192.168.0.0/16; 10.0.0.0/8; 172.16.0.0/12; fe80::/64; ::1; 127.0.0.0/8 };
options {
directory "/var/cache/bind";
// If there is a firewall between you and nameservers you want
// to talk to, you may need to fix the firewall to allow multiple
// ports to talk. See http://www.kb.cert.org/vuls/id/800113
// If your ISP provided one or more IP addresses for stable
// nameservers, you probably want to use them as forwarders.
// Uncomment the following block, and insert the addresses replacing
// the all-0's placeholder.
// forwarders {};
//========================================================================
// If BIND logs error messages about the root key being expired,
// you will need to update your keys. See https://www.isc.org/bind-keys
//========================================================================
dnssec-validation auto;
//追記
recursion yes;
allow-recursion { local-network; };
listen-on-v6 port 53 { local-network; }; //listen-on-v6の後ろにport 53を追記
listen-on port 53 { local-network; }; //追記
};
forwardersを設定すれば再起的名前解決をする際に使用するDNSサーバーの指定ができます。例えばCloudflare DNSを転送先として設定するならoptions内のforwardersのコメントアウトを外して,以下のように書けば良いです。
forwarders {
1.1.1.1;
1.0.0.1;
2606:4700:4700::1111;
2606:4700:4700::1001;
};
最後にBIND9を起動してリゾルバーの設定は完了になります。ポート開放をしていない場合はポート開放をする必要があるのでポート開放をしましょう。内部ネットワーク向けなのでルーターでのポート開放は原則不要です。
ソフトウェアファイアウォールによるポート開放
4-1.iptables,ip6tablesの場合
/etc/iptables/内のrules.v4とrules.v6の編集をします。
~~~~~~~~~~~~
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [463:49013]
:InstanceServices - [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
#追記
-A INPUT -s 192.168.0.0/16 -p tcp --dport 53 -j ACCEPT
-A INPUT -s 172.16.0.0/12 -p tcp --dport 53 -j ACCEPT
-A INPUT -s 10.0.0.0/8 -p tcp --dport 53 -j ACCEPT
-A INPUT -s 192.168.0.0/16 -p udp --dport 53 -j ACCEPT
-A INPUT -s 172.16.0.0/12 -p udp --dport 53 -j ACCEPT
-A INPUT -s 10.0.0.0/8 -p udcp --dport 53 -j ACCEPT
~~~~~~~~~~~~
COMMIT
~~~~~~~~~~~~~~~~~~~~~~~
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
#追記
-A INPUT -s fe80::/64 -p tcp --dport 53 -j ACCEPT
-A INPUT -s fe80::/64 -p udp --dport 53 -j ACCEPT
~~~~~~~~~~~~~~~~~~~~~~~
COMMIT
最後に編集したルールの反映を行います。
$ sudo iptables-restore < /etc/iptables/rules.v4
$ sudo ip6tables-restore < /etc/iptables/rules.v6
4-2. nftablesの場合(個人的に推奨)
nftコマンドが使えない場合はsudo apt-get install nftablesでnftablesのインストールをしてください。
/etc/nftables.confを編集します。文法はかなり簡単で,iptablesと異なりIPv4/IPv6を同時に扱えるのでファイル編集の手間が減ります。また,とても高速かつ軽量なのでおすすめです。過去にnftablesの解説を少しだけしてます。
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0;
policy drop;
ct state { established, related } accept
iifname "lo" accept
ip6 nexthdr icmpv6 accept
icmp type { echo-request, echo-reply } accept
icmpv6 type { echo-request, echo-reply, nd-neighbor-solicit, nd-neighbor-advert, nd-router-advert } accept
#DNSポート開放
ip saddr 192.168.0.0/16 tcp dport 53 accept
ip saddr 172.16.0.0/12 tcp dport 53 accept
ip saddr 10.0.0.0/8 tcp dport 53 accept
ip saddr 192.168.0.0/16 udp dport 53 accept
ip saddr 172.16.0.0/12 udp dport 53 accept
ip saddr 10.0.0.0/8 udp dport 53 accept
ip6 saddr fe80::/64 tcp dport 53 accept
ip6 saddr fe80::/64 udp dport 53 accept
}
chain forward {
type filter hook forward priority 0;
policy drop;
}
chain output {
type filter hook output priority 0;
policy accept;
}
}
構文に問題がないかチェックし,問題がなければnftablesを起動します。
$ sudo nft -cf /etc/nftables.conf #何も問題なければ何も表示されない。
$ sudo systemctl enable --now nftables.service
4-3. UFWの場合
一番お手軽ですね。結局はiptables/ip6tables,ebtables,arptables,ufw,firewalldのバックエンドで動いているのはnftablesですからどれ使ってもいいんですが,nftablesで一元管理できるのでできれば移行すべきだと思います。
ではポート開放ですね。実はファイル編集すらいらないので超楽です。まずはUFWの起動から行います。
$ sudo ufw enable
ではポート開放をしていきます。複数回コマンドを実行する必要があるので少々面倒かもしれません。
$ sudo ufw allow from 192.168.0.0/16 to any port 53
$ sudo ufw allow from 172.16.0.0/12 to any port 53
$ sudo ufw allow from 10.0.0.0/8 to any port 53
$ sudo ufw allow from fe80::/64 to any port 53
ポート開放ができているか確かめるにはsudo ufw statusを実行します。
$ sudo ufw status
To Action From
-- ------ ----
53 ALLOW 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8, fe80::/64
このように表示されると思います。このように表示されればOKです。
4-4. 動作確認
ここまで設定をして実際にBIND9を起動したときに起動失敗したら悲しいので動作確認をちゃんとしましょう。
$ sudo named-checkconf #実行した際に何も表示されなければ問題ない
エラーなどが特に表示されなければ問題ないのでBIND9を再起動しましょう。この際にsystemctl reload named.serviceとしてはいけません。reloadではなくrestartにしてください。でないとエラーを吐き,起動エラーが出ます。もし,やってしまった場合はrestartに書き換えて再度実行し直してください。
$ sudo systemctl restart named.service #bind9.serviceでも良いがnamed.serviceの方が確実
問題なく再起動できたらちゃんと使えるか確かめましょう。digでlocalhostを指定して正しく表示されればOKです。
$ dig @localhost
; <<>> DiG 9.18.39-0ubuntu0.24.04.2-Ubuntu <<>> @localhost
; (3 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 36166
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 13, AUTHORITY: 0, ADDITIONAL: 27
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: fb216f3ec603f2d1010000006951f577febe765d3f341fe2 (good)
;; QUESTION SECTION:
;. IN NS
;; ANSWER SECTION:
. 156888 IN NS c.root-servers.net.
. 156888 IN NS e.root-servers.net.
. 156888 IN NS l.root-servers.net.
. 156888 IN NS g.root-servers.net.
. 156888 IN NS h.root-servers.net.
. 156888 IN NS i.root-servers.net.
. 156888 IN NS b.root-servers.net.
. 156888 IN NS k.root-servers.net.
. 156888 IN NS a.root-servers.net.
. 156888 IN NS m.root-servers.net.
. 156888 IN NS d.root-servers.net.
. 156888 IN NS j.root-servers.net.
. 156888 IN NS f.root-servers.net.
;; ADDITIONAL SECTION:
a.root-servers.net. 156888 IN AAAA 2001:503:ba3e::2:30
b.root-servers.net. 156888 IN AAAA 2801:1b8:10::b
c.root-servers.net. 156888 IN AAAA 2001:500:2::c
d.root-servers.net. 156888 IN AAAA 2001:500:2d::d
e.root-servers.net. 156888 IN AAAA 2001:500:a8::e
f.root-servers.net. 156888 IN AAAA 2001:500:2f::f
g.root-servers.net. 156888 IN AAAA 2001:500:12::d0d
h.root-servers.net. 156888 IN AAAA 2001:500:1::53
i.root-servers.net. 156888 IN AAAA 2001:7fe::53
j.root-servers.net. 156888 IN AAAA 2001:503:c27::2:30
k.root-servers.net. 156888 IN AAAA 2001:7fd::1
l.root-servers.net. 156888 IN AAAA 2001:500:9f::42
m.root-servers.net. 156888 IN AAAA 2001:dc3::35
a.root-servers.net. 156888 IN A 198.41.0.4
b.root-servers.net. 156888 IN A 170.247.170.2
c.root-servers.net. 156888 IN A 192.33.4.12
d.root-servers.net. 156888 IN A 199.7.91.13
e.root-servers.net. 156888 IN A 192.203.230.10
f.root-servers.net. 156888 IN A 192.5.5.241
g.root-servers.net. 156888 IN A 192.112.36.4
h.root-servers.net. 156888 IN A 198.97.190.53
i.root-servers.net. 156888 IN A 192.36.148.17
j.root-servers.net. 156888 IN A 192.58.128.30
k.root-servers.net. 156888 IN A 193.0.14.129
l.root-servers.net. 156888 IN A 199.7.83.42
m.root-servers.net. 156888 IN A 202.12.27.33
;; Query time: 0 msec
;; SERVER: ::1#53(localhost) (UDP)
;; WHEN: Mon Dec 29 12:28:55 JST 2025
;; MSG SIZE rcvd: 851
このように表示されれば問題なく動作しているでしょう。また同じネットワークにいる別のPCからもdigでBIND9を動かしているIPアドレスを指定して動作するか確かめましょう。BIND9を動かしているPCのIPアドレスを192.168.1.254とします。
$ dig @192.168.1.254
; <<>> DiG 9.18.39-0ubuntu0.24.04.2-Ubuntu <<>> @192.168.1.254
; (3 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 36166
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 13, AUTHORITY: 0, ADDITIONAL: 27
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: fb216f3ec603f2d1010000006951f577febe765d3f341fe2 (good)
;; QUESTION SECTION:
;. IN NS
;; ANSWER SECTION:
. 156888 IN NS c.root-servers.net.
. 156888 IN NS e.root-servers.net.
. 156888 IN NS l.root-servers.net.
. 156888 IN NS g.root-servers.net.
. 156888 IN NS h.root-servers.net.
. 156888 IN NS i.root-servers.net.
. 156888 IN NS b.root-servers.net.
. 156888 IN NS k.root-servers.net.
. 156888 IN NS a.root-servers.net.
. 156888 IN NS m.root-servers.net.
. 156888 IN NS d.root-servers.net.
. 156888 IN NS j.root-servers.net.
. 156888 IN NS f.root-servers.net.
;; ADDITIONAL SECTION:
a.root-servers.net. 156888 IN AAAA 2001:503:ba3e::2:30
b.root-servers.net. 156888 IN AAAA 2801:1b8:10::b
c.root-servers.net. 156888 IN AAAA 2001:500:2::c
d.root-servers.net. 156888 IN AAAA 2001:500:2d::d
e.root-servers.net. 156888 IN AAAA 2001:500:a8::e
f.root-servers.net. 156888 IN AAAA 2001:500:2f::f
g.root-servers.net. 156888 IN AAAA 2001:500:12::d0d
h.root-servers.net. 156888 IN AAAA 2001:500:1::53
i.root-servers.net. 156888 IN AAAA 2001:7fe::53
j.root-servers.net. 156888 IN AAAA 2001:503:c27::2:30
k.root-servers.net. 156888 IN AAAA 2001:7fd::1
l.root-servers.net. 156888 IN AAAA 2001:500:9f::42
m.root-servers.net. 156888 IN AAAA 2001:dc3::35
a.root-servers.net. 156888 IN A 198.41.0.4
b.root-servers.net. 156888 IN A 170.247.170.2
c.root-servers.net. 156888 IN A 192.33.4.12
d.root-servers.net. 156888 IN A 199.7.91.13
e.root-servers.net. 156888 IN A 192.203.230.10
f.root-servers.net. 156888 IN A 192.5.5.241
g.root-servers.net. 156888 IN A 192.112.36.4
h.root-servers.net. 156888 IN A 198.97.190.53
i.root-servers.net. 156888 IN A 192.36.148.17
j.root-servers.net. 156888 IN A 192.58.128.30
k.root-servers.net. 156888 IN A 193.0.14.129
l.root-servers.net. 156888 IN A 199.7.83.42
m.root-servers.net. 156888 IN A 202.12.27.33
;; Query time: 0 msec
;; SERVER: 192.168.1.254#53(192.168.1.254) (UDP)
;; WHEN: Mon Dec 29 12:28:55 JST 2025
;; MSG SIZE rcvd: 851
このように表示されれば問題なくBIND9が動いています。BIND9でアクセスできるWebサイトなどのフィルタリングなどもすることが可能なので,色々カスタマイズして使ってみると良いかもしれません。DNS経由でのフィルタリングは結構強力なのでそれでGoogle広告系統をブロックすればYouTubeの広告もブロックできるかもしれませんね。AdGuard Homeで自宅にAdGuard DNSサーバーを建てて広告ブロックをするみたいなこともできたりするらしいですが,時間あるときに試してみたいですね。
4-5. クライアント側の設定
Windowsであればネットワーク設定で接続しているWi-Fiやイーサネットの詳細からDNSサーバーの編集で,DNSサーバーを動かしているIPアドレス(例:192.168.1.9など)を指定すればシステムのデフォルトでそのDNSサーバーを使うようになります。
iOS/iPadOS/macOSの場合は,繋いでいるWi-Fiやイーサネットの詳細でDNSの構成という項目からDNSサーバーを追加します。その際にDNSサーバーを動かしているIPアドレスを追加すれば良いです。
Linuxなどの場合は/etc/resolv.confを編集すれば良いです。nameserverの後にIPアドレスを指定すればOKです。これはmacOS/BSD系でも同じようにできるはずです。ただ,macOSの場合は利き方が中途半端なのでこの方法ではなく上記の方法でやることをお勧めします。
# This is /run/systemd/resolve/resolv.conf managed by man:systemd-resolved(8).
# Do not edit.
#
# This file might be symlinked as /etc/resolv.conf. If you're looking at
# /etc/resolv.conf and seeing this text, you have followed the symlink.
#
# This is a dynamic resolv.conf file for connecting local clients directly to
# all known uplink DNS servers. This file lists all configured search domains.
#
# Third party programs should typically not access this file directly, but only
# through the symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a
# different way, replace this symlink by a static file or a different symlink.
#
# See man:systemd-resolved.service(8) for details about the supported modes of
# operation for /etc/resolv.conf.
nameserver 1.1.1.1
nameserver 2606:4700:4700::1111
5.外部ネットワーク向け(権威DNSサーバーの構築)
オープンリゾルバーはあまりよろしくないので,あまり構築の仕方を書くつもりはないですが,上記の内部ネットワーク向けでnamed.conf.optionsのallow-recursion { any; };に設定すればオープンリゾルバーになります。セキュリティを高めたいなら,sysctlでのカーネルパラメーターでSYNパケットの量の調節なりをすると良いかもしれません。
話が脱線しましたが,権威DNSサーバーの構築をやっていきましょう。まずは権威サーバーを建てるためにドメインが必要です。ドメインを所持していることを前提に話しますので,ドメインの取得などの話は割愛させていただきます。
権威サーバーを運用するにあたって最低限必要なDNSレコードは,SOA,NSの2種類とA,AAAAのいずれかの最低3種類です。NSレコードは2つ,SOAレコードは1つなので割り当ては最低3つすることになります。NSレコードを割り当てする際に指定するネームサーバーのドメインにA,AAAAレコードのいずれかでIPアドレスの割り当てが必要なので,累計4つ以上のレコードを必要とします。
グダグダ書いててても分かりづらいので実際に.confファイルの編集をしていきましょう。まずは,named.conf.optionsの設定からです。
acl local-network { ::1; 127.0.0.0/8; 192.168.0.0/16; 172.16.0.0/12; 10.0.0.0/8; fe80::/64; };
options {
directory "/var/cache/bind";
// If there is a firewall between you and nameservers you want
// to talk to, you may need to fix the firewall to allow multiple
// ports to talk. See http://www.kb.cert.org/vuls/id/800113
// If your ISP provided one or more IP addresses for stable
// nameservers, you probably want to use them as forwarders.
// Uncomment the following block, and insert the addresses replacing
// the all-0's placeholder.
// forwarders {
// 0.0.0.0;
// };
//========================================================================
// If BIND logs error messages about the root key being expired,
// you will need to update your keys. See https://www.isc.org/bind-keys
//========================================================================
dnssec-validation auto;
// このように設定するか,もしくは recursion no;に設定する。
// その場合はallow-recrsionの設定は無視される。
recursion yes;
allow-recursion { local-network; };
//ポート番号は書かなくても良いが明示的に書いておくことを推奨する。
listen-on port 53 { any; };
listen-on-v6 port 53 { any; };
};
次に,named.conf.localを編集します。これは権威サーバーとして動かすドメイン名の記入とゾーンファイルの記入などを行います。
//
// Do any local configuration here
//
// Consider adding the 1918 zones here, if they are not used in your
// organization
//include "/etc/bind/zones.rfc1918";
// ""内に指定するドメインは管理したいドメインを入力する。
// 例えばssh.example.comをサブドメインとして管理したい場合は,""内に
// example.comと入力してゾーンファイルに書く際にサブドメインで設定する。
zone "example.com" {
type master;
file "/var/lib/bind/db.example.com;
allow-update { none; };
};
次にゾーンファイルの設定をします。デフォルトではvar/lib内にはbindディレクトリが存在しないのでディレクトリを作成します。また,その際にパーミッションをchownでbind:bindに設定し直します。
$ sudo mkdir -p /var/lib/bind/
$ sudo chown -R bind:bind /var/lib/bind
これらの設定ができたら,fileに指定したパスにゾーンファイルを作成し記入していきます。以下はゾーンファイルの例です。参考にしてください。設定し終わったらゾーンファイルの所有者をbind:bindにすることを忘れないようにしましょう。
$TTL 3600; 1hour, TTLはTime To Liveの略
@ IN SOA ns1.example.com. ns2.example.com. (
1 ; Serial
3600 ; Refresh
1800 ; Retry
2592000 ; Expire
3600 ; Minium
)
;Name Server
@ IN NS ns1.example.com.
@ IN NS ns2.example.com.
;A Record
ns1 IN A 23.75.13.8
;AAAA Record
ns2 IN AAAA 2001:4865:4280:ad01:fa23::1
$ sudo chown bind:bind /var/lib/bind/db.example.com
#ゾーンファイルをtouch,viやnanoで作成・編集する際に
#sudo -u bindとして実行しているなら実行しなくても良い。
このように書くと良いでしょう。;の後ろにコメントとしてこのように書くとどのレコードを設定しているかの見分けが簡単になるのでオススメです。レコードの種類で区切るも良いですし,iCloudのカスタムメールのためのDNSレコード群のようにまとめるなどでも良いのでグループ化すると分かりやすいと思います。
NSレコード用のAレコードやAAAAレコードを割り当てする際は,53/TCPと53/UDPを開いているIPアドレスの指定をするべきです。NSレコードの役割は権威DNSサーバーを指定することなので,権威DNSサーバーが53/UDPと53/TCPが開いていないのは大問題です。なぜなら外部からの問い合わせによる名前解決ができないからです。
なので,最低限パケットフィルタリングの設定でこれらのアドレスの53/TCP,53/UDPは外部から通信が入れるようにする必要があります。フレッツ光クロス・フレッツ光ネクスト(IPoE)を使っている場合は設定が少々面倒です。MAP-E形式であればポート開放ができるので,この形式のIPv4 over IPv6が使えるコラボ光・プロバイダーを選ぶと良いと思います(例:OCN光,en光,BIGLOBE光,CyberBBなど)。DS-Lite方式でもポート開放ができないわけではないですがその場合はIPv4でPPPoE方式も使用できる場合のみだった記憶があります。私はDS-Lite方式のプロバイダーを使用しない主義なのでDS-Lite方式の仕様はよく知らないのでこの場合はどうするべきかは分からないです(申し訳ないです)...。PPPoEの場合はルーターからポート開放の設定を簡単にできるので気にしなくて良いはずです。
MAP-Eとは
RFC7597のMapping of Address and Port with Encapsulationの略で,IPv4パケットをカプセル化してIPv6パケット上で使えるようにする技術のことです。MAP方式には他にもMAP-Tと呼ばれるアドレス変換技術もありますが,日本ではMAP-Eが主流です。
フレッツNGNにおけるMAP-Eは1つのIPv4アドレスのポート(1024~65535)を240個単位でMAP-E使用をしているクライアントに分配するのでIPv4アドレスが固定されるので,IPv6アドレスでもポート開放(正しくはパケットフィルタリング)をすることができます。フレッツにおけるMAP-Eの場合はウェルノウンポートで外部に公開できないので,http://192.168.1.1:8888/tから「静的NAPT設定」と「IPv4パケットフィルタ設定」から別のポートへ変換する必要があります。ただし,これは固定IP契約をしていない場合の話なので固定IP契約している場合は使えるポートに制限がされることはありません。
5-1. BIND9の動作確認
named.conf.options,named.conf.localやゾーンファイルの記入ができたらまずは構文エラーがないかを確かめます。問題がなければプロセスを再起動します。パケットフィルタの設定ができたら名前解決できるか確かめます。その際は権威サーバーだけでなく外部のオープンリゾルバーやルーターのDNSからも確認できるかを確かめます。
$ sudo named-checkconf #named.conf系のファイルの構文確認
$ sudo named-checkzone example.com. /var/lib/bind/db.example.com #ゾーンファイルの確認
問題がなければnamed-checkconfは何も表示されず,named-checkzoneはOKと表示されます。問題がないことがわかればプロセスを再起動します。
$ sudo systemctl restart named.service # bind9.serviceでも良いがnamed.serviceの方が確実
$ sudo rndc reload #ゾーンファイルの読み直し。successfulと出れば問題なし
まずはローカルの権威サーバーで名前解決できるかを検証しましょう。ゾーンファイルに設定した内容が適用されているかを調べます。
$ dig @192.168.1.254 ns1.example.com. a
; <<>> DiG 9.20.17 <<>> @192.168.1.254 ns1.example.com. a
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 7014
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;ns1.example.com. IN A
;; ANSWER SECTION:
ns1.example.com. 3600 IN A 23.75.13.8
;; Query time: 12 msec
;; SERVER: 192.168.1.254#53(192.168.1.254) (UDP)
;; WHEN: Mon Dec 29 13:51:02 JST 2025
;; MSG SIZE rcvd: 72
このように表示されれば問題ありません。正常に設定できています。ここまでできたらパケットフィルタの設定をしていきましょう。
5-2. パケットフィルタリングやファイアウォールの設定
まずは,ソフトウェアファイアウォールの設定をしていきましょう。nftablesでの設定を紹介をします。iptablesやufw,firewalldでも同じように設定できると思いますが紹介はしません。arptables,ebtables,firewalld,iptables/ip6tables,ufwのバックエンドで動作するのはnftablesなので初めからnftablesで設定できるように慣れておくと良いかもしれません。ufw,firewalldはPythonスクリプトでarptables,ebtables,iptables/ip6tablesはC/C++で書かれています。ですが同じくC/C++で書かれているnftablesの方が動作も速く軽量なので私は普段からnftablesを使用するようになりました。
では,nftablesのインストールからしていきましょう。デフォルトで入っているかもしれませんが,不安であればaptやdpkgでインストールされているか確認するといいでしょう。
$ sudo apt-get install nftables
デフォルトではnftablesは使用されないようになっているのでsystemdから自動起動するように設定をしましょう。
# --nowを付けることで自動起動を有効にするときについでに起動できる。
$ sudo systemctl enable --now nftables.service
自動起動設定が有効にできたら/etc/nftables.confを編集していきます。私はIPアドレス単位でのフィルタリングをするのでiproute2でIPv4,IPv6アドレスを確認してから設定しています。UbuntuはデフォルトでIPv6アドレスの一時アドレスを生成するモードが有効になっているのでこれを無効にした上でIPv6アドレスをわかりやすいように固定します。IPv6アドレスの一時アドレスの自動生成はカーネルパラメーターにより設定されているのでsysctlで無効にします。しなくても良いですが,しておいた方が後々楽かもしれません。個人的には推奨します。
net.ipv4.conf.default.rp_filter=1
net.ipv4.conf.all.rp_filter=1
net.ipv4.tcp_syncookies=1
net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1
net.ipv6.conf.all.use_tempaddr =0
net.ipv6.conf.default.use_tempaddr =0
net.ipv6.conf.all.use_tempaddr = 0
net.ipv6.conf.default.use_tempaddr = 0
forwardやfilterと書かれている部分のコメントアウトは外さなくても良いですが,tcp_syncookiesはコメントアウトを外しましょう。Syn Flood攻撃を軽減できます。デフォルトで今のLinuxは有効らしいですが明示的に有効にすると良いと思います。一番下のnet.ipv6.conf.all.use_tempaddr=0とnet.ipv6.conf.default.use_tempaddr=0がUbuntuでは2が標準なので0に設定し直しています。このようにすることでIPv6アドレスの一時アドレスが生成されなくなるのでややこしくなくなります。DebianやRHEL系はデフォルトで0なんですけどね。
設定できたらsysctl -pで適用します。sysctl -pで即時に適用されますが念のため再起動を行います。
$ sudo sysctl -p
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.tcp_syncookies = 1
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
net.ipv6.conf.all.use_tempaddr = 0
net.ipv6.conf.default.use_tempaddr = 0
$ reboot
設定ができたら次はIPv6アドレスの変更をします。デフォルトではMACアドレスが後半64bitになっているのでもっと分かりやすいアドレスに変えます。まずは割り当てされているIPv6 prefixの確認をしていきましょう。ifconfigは古いらしいのでipコマンドを使います。
$ ip -6 a s scope global
2: eno1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
inet6 240b:xxxx:xxxx:xxxx:146e:451a:a463:d059/64 scope global noprefixroute
割り当てされている場合はこのように2から始まるIPv6アドレスが割り当てされているはずです。ですが,このアドレスは分かりづらいです。なのでアドレスを変更します。/64になっているので前半64bitは変えられませんから,後半の64bitを好きに変更します。私はよく240b:xxxx:xxxx:xxxx::1/64のようにしたりして分かりやすくしています。nmcliコマンドで変更していきます。この際にゲートウェイアドレスも設定しないとIPv6での通信ができなくなってしまうので気をつけましょう。ゲートウェイアドレスを調べましょう。
$ ip -6 neigh |grep router
fe80::1e7c:98ff:fec5:aabc dev eno1 lladdr 1c:7c:98:c5:aa:bc router REACHABLE
240b:xxxx:xxxx:xxxx:1e7c:98ff:fec5:aabc dev eno1 lladdr 1c:7c:98:c5:aa:bc router REACHABLE
fe80::1e7c:98ff:fec5:aabc dev ens2f0 lladdr 1c:7c:98:c5:aa:bc router STALE
fe80::1e7c:98ff:fec5:aabc dev ens2f1 lladdr 1c:7c:98:c5:aa:bc router STALE
240b:xxxx:xxxx:xxxx:1e7c:98ff:fec5:aabc dev ens2f0 lladdr 1c:7c:98:c5:aa:bc router STALE
240b:xxxx:xxxx:xxxx:1e7c:98ff:fec5:aabc dev ens2f1 lladdr 1c:7c:98:c5:aa:bc router STALE
このように表示されると思います。この場合のゲートウェイアドレスは2から始まるIPv6アドレスです。これをゲートウェイアドレスとして設定します。ではやっていきます。例ではネットワークインターフェース名をeno1としています。
$ sudo nmcli con modify eno1 ipv6.method auto
$ sudo nmcli con modify eno1 ipv6.method manual
$ sudo nmcli con modify eno1 ipv6.gateway 240b:xxxx:xxxx:xxxx:xxxx:1e7c:98ff:fec5:aabc
$ sudo nmcli con modify eno1 ipv6.address 240b:xxxx:xxxx:xxxx::1/64
$ sudo nmcli con up eno1
最初にmanualとして実行しても良いんですがエラーが出ることがあるのでautoを実行してからmanualを実行することを推奨します。次にipv6.gatewayに上記で調べたゲートウェイアドレスを指定します。この際にCIDR表記する必要はありません。
次にipv6.addressですが,この部分を好きに変更できます。前半64bitはNTT/プロバイダーから割当されているものなので変更できませんが,後半は変更できるので自分にとって分かりやすいアドレスに変えると良いでしょう。アドレスを指定する際はCIDR表記で/64をつけることを推奨します。
設定ができたら,sudo nmcli con up eno1で適用します。再度ipコマンドで設定したようにできているか確認しましょう。
$ ip -6 a s scope global
2: eno1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
inet6 240b:xxxx:xxxx:xxxx::1/64 scope global noprefixroute
では,ここからやっとnftables.confの設定をします。では編集していきましょう。
#!/usr/sbin/nft -f
flush ruleset
table filter inet {
chain input {
type filter hook input priority 0;
policy drop;
ct state { established, related } accept
iifname "lo" accept
ip6 nexthdr icmpv6 accept
icmp type { echo-request, echo-reply } accept
icmpv6 type { echo-request, echo-reply, nd-neighbor-solicit, nd-neighbor-advert, nd-router-advert } accept
#DNS
ip daddr 192.168.1.254/24 tcp dport { 53, 443, 853 } accept
ip daddr 192.168.1.254/24 udp dport 53 accept
ip6 daddr 240b:xxxx:xxxx:xxxx::1 tcp dport { 53, 443, 853 } accept
ip6 daddr 240b:xxxx:xxxx:xxxx::1 udp dport 53 accept
}
chain forward {
type filter hook forward priority 0;
policy drop;
}
chain output {
type filter hook output priority 0;
policy accept;
}
}
設定ファイルが書けたら構文に問題がないかを確認します。問題があればどの部分が問題かを表示してくれます。問題なければ何も表示はされません。
設定でTCPポートに443と853がありますがこれはDNS over HTTPSとDNS over TLSを設定するつもりがない場合は開く必要はありませんので,53だけで良いです。設定したい場合は開いておくと良いでしょう。
$ sudo nft -cf /etc/nftables.conf
問題がなかったらnftablesを再起動します。
$ sudo systemctl restart nftables.service
ソフトウェアファイアウォールの設定は終わったので次はルーターでのパケットフィルタ設定をする必要があります。かなり面倒かもしれませんが,これができていないと外部から名前解決ができないので自前で権威サーバーの管理ができていることにはなりません。例としてNTTのレンタルルーターでのやり方を書くので,それ以外の場合は別途やり方を調べてください。おそらくはポート開放するだけだとは思います。
IPv6パケットフィルタリング
IPv6(IPoE)パケットフィルタリングの設定の方がIPv4でやるより簡単なはずなのでまずはそちらからやります。下記の画像のように宛先IPv6 Prefix/Prefix長の設定をします。240b:xxxx:xxxx:xxxx::1/64の場合はPrefixの方に240b:xxxx:xxxx:xxxx::1を,Prefix長の方に64を設定します。これらを設定するときは,右側の編集を押して編集します。UDPとTCPは同時に設定できないのでそれぞれ設定します。また,ポート番号毎にも設定を書く必要があります。53/TCPや53/UDPを選んで設定をするとdomainと表示されますが正常なので問題ありません。設定ができたらIPv6セキュリティレベルを高度にし,左側のチェックボックスにチェックを入れて,左下の設定を押して設定を適用します。これでIPv6の設定は完了です。下記の画像は設定例です。

IPv4パケットフィルタリング
まずは, https://192.168.1.1:8888/tにアクセスします。以下のような表示になると思います。

IPv4設定を選び,パケットフィルタリング設定をします。移動すると以下のような表示になると思います。
画像は固定IP契約時の場合の表示です。

固定IPを契約していない場合は利用可能ポートが細かく合計240個書いてあると思います。こちらにアクセスして設定をしたことがない人は,まずは新しくユーザー名とアカウント名を決めて登録をする必要があります。ここの説明は割愛させてもらいます。アカウントにログインできたら,「IPv4パケットフィルタ設定」と「静的NAPT設定」を編集します。片方だけ設定しても外部からの通信は通さないので必ず両方設定してください。編集するときはNO.列の数字の部分をクリックすると編集することができます。送信元にはanyを,宛先にはBIND9を動かしているPCのIPv4アドレスを指定しましょう。方向はWAN=>LANか両方向を選んでください。
編集例は以下のようになります。
・IPv4パケットフィルタ設定の場合

・静的NAPT設定の場合

これらが設定できたらパケットフィルタの設定は完了です。外部からの問い合わせができるかを確かめましょう。
5-3.動作確認
あとは外部からの問い合わせに対応できるかを確かめます。問題がなければ正常にDNSクエリが返ってきます。問題があればSERVFAILとなって返ってきますので何か問題があることが分かります。確かめるときはオープンリゾルバー(Cloudflare DNS, Google DNS, Quad9 DNSなど)からの問い合わせと,ルーターのDNSサーバーからの問い合わせで確かめましょう。
$ dig @1.1.1.1 ns1.example.com. a #Cloudflare DNSの場合
; <<>> DiG 9.20.17 <<>> @1.1.1.1 ns1.example.com. a
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 7014
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;ns1.example.com. IN A
;; ANSWER SECTION:
ns1.example.com. 3600 IN A 23.75.13.8
;; Query time: 12 msec
;; SERVER: 1.1.1.1#53(1.1.1.1) (UDP)
;; WHEN: Mon Dec 29 13:51:02 JST 2025
;; MSG SIZE rcvd: 72
このように出れば正常に設定ができています。問題がある場合はstatus:の部分にSERVFAILのように表示されるはずです。Cloudflare DNSだけでなく他のGoogle DNSやルーターのDNSでも名前解決できるかを検証しましょう。
$dig @192.168.1.1 ns1.example.com. a
; <<>> DiG 9.20.17 <<>> @192.168.1.1 ns1.example.com. a
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 7014
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;ns1.example.com. IN A
;; ANSWER SECTION:
ns1.example.com. 3600 IN A 23.75.13.8
;; Query time: 12 msec
;; SERVER: 192.168.1.1#53(192.168.1.1) (UDP)
;; WHEN: Mon Dec 29 13:51:02 JST 2025
;; MSG SIZE rcvd: 72
問題がなければこのようになります。問題があれば同様にSERVFAILと表示されます。
オープンリゾルバー
Cloudflare DNSのIPアドレス
・IPv4アドレス
1.1.1.1, 1.0.0.1 (何もフィルタリングなし,ドメイン名:one.one.one.one)
1.1.1.2, 1.0.0.2 (マルウェアのフィルタリングあり,ドメイン名:security.cloudflare-dns.com)
1.1.1.3, 1.0.0.3 (マルウェア・アダルトコンテンツのフィルタリングあり,ドメイン名:family.clouflare-dns.com)
・IPv6アドレス
2606:4700:4700::1111,2606:4700:4700::1001 (何もフィルタリングなし,ドメイン名:one.one.one.one)
2606:4700:4700::1112,2606:4700:4700::1002 (マルウェアのフィルタリングあり,ドメイン名:security.cloudflare-dns.com)
2606:4700:4700::1113,2606:4700:4700::1003 (マルウェア・アダルトコンテンツのフィルタリングあり,ドメイン名:family.clouflare-dns.com)
2606:4700:4700::64,2606:4700:4700::6400 (DNS64,何もフィルタリングなし,ドメイン名:dns64.cloudflare-dns.com)
Google DNSのIPアドレス
・IPv4アドレス
8.8.8.8,8.8.4.4 (何もフィルタリングなし,ドメイン名:dns.google)
・IPv6アドレス
2001:4860:4860::8888,2001:4860:4860::8844 (何もフィルタリングなし,ドメイン名:dns.google)
2001:4860:4860::6464,2001:4860:4860::64 (DNS64,何もフィルタリングなし,ドメイン名:dns64.dns.google)
Quad9 DNSのIPアドレス
・IPv4アドレス
9.9.9.9,149.112.112.9 (マルウェアのフィルタリングあり,ドメイン名:dns9.quad9.net)
・IPv6アドレス
2620:fe::9,2620:fe::fe:9 (マルウェアのフィルタリングあり,ドメイン名:dns9.quad9.net)
他にもオープンリゾルバーはありますがこの記事で紹介するのは上記の3つです。マルウェアフィルタリングの強さはQuad9 > Cloudflare DNSのようです。アダルトコンテンツのフィルタリングが可能なのは大手のリゾルバーだとCloudflare DNSくらいかもしれません(他にもあるかもですが調べきれていないです...)。
オープンリゾルバーによる検証とルーターDNSによる検証が正常にできたら権威DNSサーバーの構築は完了です。あとはおまけでDNSSECの設定やDoH/DoTの設定の仕方について書こうと思います。DNSSECの設定については諸説あるので設定するかどうかはその人次第です。人によっては無駄だと言う人もいます。私は設定しようがしなかろうがリスクの差は変わらないと考えているので,それなら設定しておこうと思って設定しています。ただ,設定をミスするとGoogle DNSやCloudflare DNSでの名前解決ができなくなるので注意が必要です。
おまけ(DoH,DoT,DNSSECの設定)
DoHはDNS over HTTPSの略で名前解決する際にHTTPSプロトコルを使うやり方です。HTTPSを使用するのでDNSクエリが暗号化されます。HTTPSパケットと混ざるのでWebへアクセスしているのか名前解決しているのかの判断を困難にします。クライアント側が使用するセキュリティ向上するための技術です。また,HTTPSパケットと混ざるので検閲回避に使用できる場合があります。
次にDoTはDNS over TLSの略で名前解決する際にTLSプロトコルを使用しDNSクエリを暗号化するやり方です。デフォルトでは853/TCPを使うのでDoHと違って検閲回避に使用はできないです。DoHと違い,TLSプロトコルを使うので比較的シンプルです。
DNSSECはDomain Name System Security Extentionsの略でDNSのセキュリティ拡張機能です。正直仕様が複雑で難しく説明できたもんじゃないですが,電子署名と公開鍵認証によるキャッシュポイズニング対策をするための機能だと思います。ただ,キャッシュポイズニング対策としては不完全と言われています。また他にもDNSSECが有効だとDNSクエリが肥大化するのでDDoS攻撃のリスク(リフレクション攻撃など)が上がりやすいです。また,他にもDNSSEC検証未対応なリゾルバーに対しての脆弱性があるとも言われています。現にDNSSECを設定していない企業もあり,AppleやAmazonなどの大企業のように設定していない企業もあります。Google DNSやCloudflare,Quad9,Akamaiなどは設定しています。一部インターネット関連の企業は設定していることが多いと思われます。
話が色々脱線した気がしますが,それぞれの設定の仕方について話していきます。DoHとDoTに関しては設定ほぼ一緒なので同時に説明します。
・DoH,DoTの設定
named.conf.optionsの編集もしますが,Let's Encryptなどから取得したTLS証明書が必要です。まずはTLS証明書を取得しましょう。もしくは自己証明書でも良いですがLet's Encryptなどから取得した証明書を利用することを推奨します。webrootモードでcertbotを使って証明書を取得しても良いですし(HTTP-01),RFC2136のDNS-01 Challengeで取得するようにしても良いです。RFC2136で設定するのは少々複雑ですのでこの記事では割愛させてください(今後記事編集した際に追記するかもしれないです...期待しないで...)。
NginxでHTTP-01 Challengeさせるので,まずはNginxとCertbotをインストールします。Apache2でも良いですがここではApache2でのやり方は紹介しません。
$ sudo apt-get install nginx certbot
インストールができたらNginxの設定をしていきましょう。証明書を取得するためのconfファイルを書いていきます。/etc/nginx/conf.dディレクトリ内に新しくconfファイルを設置しましょう。
$ cd /etc/nginx/conf.d/
$ sudo touch dns-cert.conf #分かりやすい名称をつけておくことを推奨。
server {
listen 80;
listen [::]:80; #IPv6アドレスを使用する場合は追記
server_name ns1.example.com;
location /.well-known/acme-challenge/ {
root /var/www/html;
}
# その他のリクエストは拒否,あるいは適当なページを表示
location / {
return 404;
}
}
$ sudo nginx -t # test is successfulと表示されればOK
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Apache2が入って起動しておりNginxが起動できない場合はApache2を削除するか動きを止めましょう。下記のいずれかを実行しましょう。その後に再度Nginxを起動し直してみてください。
$ sudo systemctl disable --now apache2.service #自動起動と動作の停止
$ sudo apt-get autoremove apache2 #パッケージの削除
$ sudo systemctl restart nginx.service #サービスの再起動
$ sudo systemctl enable nginx.service #サービスの自動起動有効化
ではCertbotで証明書の取得をします。
$ sudo certbot certonly --webroot -d ns1.example.com -d ns2.example.com -w /var/www/html
正常にいけばSuccessfullyと表示されるのでそれを使います。Crontabで2ヶ月毎に更新するように設定すれば良いでしょう(Let's Encryptの証明書の有効期限が90日のため)。この場合はおそらく/etc/letsencrypt/live/ns1.example.com/内にfullchain.pemとprivkey.pemがあるのでこれを利用します。また,別途DH鍵をOpenSSLコマンドで作成します。時間が少々かかるので気長に待ちましょう。
$ sudo openssl dhparam -out /var/lib/bind/dhparam.pem 3072
作成ができたらファイルのパーミッション設定などを行います。
$ sudo find /etc/letsencrypt/{live,archive} -type d -exec chmod 755 {} + #ディレクトリのモードを変更
$ sudo find /etc/letsencrypt/{live,archive} -type f -exec chmod 644 {} + #ファイルのモードを変更
$ sudo chown bind:bind /var/lib/bind/dhparam.pem #所有者をrootからbindへ変更
では,named.conf.optionsに追記をしていきます。
tls local-tls {
key-file "/etc/letsencrypt/live/ns1.example.com/privkey.pem";
cert-file "/etc/letsnencrypt/live/ns1.example.com/fullchain.pem";
dhparam-file "/var/lib/bind/dhparam.pem";
};
http local {
endpoints { "/dns-query"; };
};
acl local-network { ::1; 127.0.0.0/8; 192.168.0.0/16;
172.16.0.0/12; 10.0.0.0/8;
fe80::/64; 240b:xxxx:xxxx:xxxx::/64 };
options {
directory "/var/cache/bind";
// If there is a firewall between you and nameservers you want
// to talk to, you may need to fix the firewall to allow multiple
// ports to talk. See http://www.kb.cert.org/vuls/id/800113
// If your ISP provided one or more IP addresses for stable
// nameservers, you probably want to use them as forwarders.
// Uncomment the following block, and insert the addresses replacing
// the all-0's placeholder.
// forwarders {
// 0.0.0.0;
// };
//========================================================================
// If BIND logs error messages about the root key being expired,
// you will need to update your keys. See https://www.isc.org/bind-keys
//========================================================================
dnssec-validation auto;
// このように設定するか,もしくは recursion no;に設定する。
// その場合はallow-recrsionの設定は無視される。
recursion yes;
allow-recursion { local-network; };
listen-on port 53 { any; };
listen-on-v6 port 53 { any; };
//下記は追記
//DNS over HTTPS 443/tcp
listen-on port 443 tls local-tls http local { any; };
listen-on-v6 port 443 tls local-tls http local { any; };
//DNS over TLS 853/tcp
listen-on port 853 tls local-tls { any; };
listen-on-v6 port 853 tls local-tls { any; };
};
設定ファイルに追記が終わったら構文チェックをし,問題がなければプロセスの再起動を行いましょう。
$ sudo named-checkconf #問題がなければ何も表示されない。
$ sudo systemctl restart named.service #bind9.serviceでも良いがnamed.serviceの方が確実。
プロセスが再起動できたら動作確認をしましょう。ポートはそれぞれDoHの場合は443/TCP,DoTの場合は853/TCPが開いていればOKです。上記で紹介したやり方でパケットフィルタの設定をしましょう。DoHの場合は+httpsを,DoTの場合は+tlsをオプションとして付け足して実行してください。問題なければ以下のような表示がされて,status: NOERRORとなるはずです。実際に他のドメインの名前解決ができるか,または権威サーバーで設定したなら運用しているドメインに対して別のクライアントからやってみてください。
$ dig +https @192.168.1.254 #DoHの場合は+https, DoTの場合は+tls
; <<>> DiG 9.18.39-0ubuntu0.24.04.2-Ubuntu <<>> @192.168.1.254 +https
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 17366
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 13, AUTHORITY: 0, ADDITIONAL: 27
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: 3da8133d53c8b5fc01000000695279a559ea9f8532e660c8 (good)
;; QUESTION SECTION:
;. IN NS
;; ANSWER SECTION:
. 515827 IN NS h.root-servers.net.
. 515827 IN NS j.root-servers.net.
. 515827 IN NS e.root-servers.net.
. 515827 IN NS b.root-servers.net.
. 515827 IN NS m.root-servers.net.
. 515827 IN NS f.root-servers.net.
. 515827 IN NS d.root-servers.net.
. 515827 IN NS g.root-servers.net.
. 515827 IN NS a.root-servers.net.
. 515827 IN NS i.root-servers.net.
. 515827 IN NS c.root-servers.net.
. 515827 IN NS l.root-servers.net.
. 515827 IN NS k.root-servers.net.
;; ADDITIONAL SECTION:
a.root-servers.net. 515827 IN AAAA 2001:503:ba3e::2:30
b.root-servers.net. 515827 IN AAAA 2801:1b8:10::b
c.root-servers.net. 515827 IN AAAA 2001:500:2::c
d.root-servers.net. 515827 IN AAAA 2001:500:2d::d
e.root-servers.net. 515827 IN AAAA 2001:500:a8::e
f.root-servers.net. 515827 IN AAAA 2001:500:2f::f
g.root-servers.net. 515827 IN AAAA 2001:500:12::d0d
h.root-servers.net. 515827 IN AAAA 2001:500:1::53
i.root-servers.net. 515827 IN AAAA 2001:7fe::53
j.root-servers.net. 515827 IN AAAA 2001:503:c27::2:30
k.root-servers.net. 515827 IN AAAA 2001:7fd::1
l.root-servers.net. 515827 IN AAAA 2001:500:9f::42
m.root-servers.net. 515827 IN AAAA 2001:dc3::35
a.root-servers.net. 515827 IN A 198.41.0.4
b.root-servers.net. 515827 IN A 170.247.170.2
c.root-servers.net. 515827 IN A 192.33.4.12
d.root-servers.net. 515827 IN A 199.7.91.13
e.root-servers.net. 515827 IN A 192.203.230.10
f.root-servers.net. 515827 IN A 192.5.5.241
g.root-servers.net. 515827 IN A 192.112.36.4
h.root-servers.net. 515827 IN A 198.97.190.53
i.root-servers.net. 515827 IN A 192.36.148.17
j.root-servers.net. 515827 IN A 192.58.128.30
k.root-servers.net. 515827 IN A 193.0.14.129
l.root-servers.net. 515827 IN A 199.7.83.42
m.root-servers.net. 515827 IN A 202.12.27.33
;; Query time: 0 msec
;; SERVER: 192.168.1.254#443(192.168.1.254) (HTTPS)
;; WHEN: Mon Dec 29 21:52:53 JST 2025
;; MSG SIZE rcvd: 851
下の方の;; SERVER:の欄にDoHの場合は#443とHTTPSが,DoTの場合は#853とTLSが表示されます。ちなみにオープンリゾルバーであるCloudflare DNS,Google DNS,Quad9などはDoTとDoHの両方に対応しています。対応していないオープンリゾルバーもあるかもしれません。
・DNSSECの設定
ゾーンファイルを編集した際に再度ZSKとKSKで再度手動で署名するのは面倒なのでBIND9.9から実装されたインラインサイニングを使用します。インラインサイニングを利用することでBIND9が勝手に署名し直してくれるので私たちが直接署名し直す必要がないので楽です。ただ,DNSSECを設定するにはDNSSECの設定に対応したドメインレジストラを使う必要があります(Namecheap, Spaceshipなどが対応している)。GMO系列のレジストラ(お名前.comなど)のように特定のドメインしか対応していなく,尚且つ有料とかいうゴミカスレジストラもあるので注意してください。.jpドメインやxx.jpドメインなどを使用しない限りは基本はドメインの取得は海外レジストラに頼るべきです。海外レジストラは優しいので無料で全てのTLDに対してDNSSECを使わせてくれるのでおすすめです。私はNampcheapを使おうと思ったのですが.workドメインの移管に対応していないと言われたので対応しているSpaceshipを使ってくれと言われたのでそちらのレジストラを使わせてもらってます。移管元は~~某お⚪︎前.com~~です。なんで最初にここ使ったんだろう...?っていう後悔を未だにしてます。気を付けましょう。
話が脱線し過ぎたので,設定をしていきましょう。まずはnamed.conf.optionsを編集し追記をします。
~~~~~~~~~~~~~~~~~~~
options {
directory "/var/cache/bind";
key-directory "/var/lib/bind/key"; //追記
// If there is a firewall between you and nameservers you want
// to talk to, you may need to fix the firewall to allow multiple
// ports to talk. See http://www.kb.cert.org/vuls/id/800113
~~~~~~~~~~~~~~~~~~
};
では,ZSKとKSKを保存するディレクトリの作成をしましょう。ディレクトリを作成する際は所有者がbind:bindになるようにします。
$ sudo -u bind mkdir -p /var/lib/bind/key
ディレクトリの作成ができたら,named.conf.localを編集します。
//必ず「zone "example.com"」の上の行に追記する。
dnssec-policy "ed25519-policy" {
keys {
ksk lifetime unlimited algorithm ed25519;
zsk lifetime 60d algorithm ed25519;
};
};
zone "example.com" {
type master;
inline-signing yes;
dnssec-policy "ed25519-policy";
file "/var/lib/bind/db.example.com";
allow-update { none; };
};
acl trusted {
192.168.0.0/16;
};
view "internal" {
match-clients { "trusted"; };
recursion yes;
allow-recursion { any; };
zone "example.com" {
type master;
file "/var/lib/bind/db.example.com";
};
};
view "external" {
match-clients { any; };
recursion no;
zone "example.com" {
type master;
allow-update { none; };
file "/var/lib/bind/db.example.com";
};
};
viewで条件を分けても良いですが,設定が結構難しくなります。オープンリゾルバーと権威サーバーを同時に動かしたい場合は使うと良いかもしれません。試したことないので時間あるとき試してやり方を追記しときます。
設定ファイルの編集が終わったら構文チェックをし,問題なければプロセスを再起動します。
$ sudo named-checkconf
$ sudo systemctl restart named.service
プロセスの再起動が正常に完了したらレジストラにDSレコードの登録を行います。これを行わないとオープンリゾルバーでの名前解決時にBogusとなりstatus: SERVFAILと表示され名前解決が正常にできません。登録するDNSレコードは以下のようにして確認します。DSレコードの登録の仕方はレジストラによって違うので各自で調べてください。
$ dig @localhost example.com. ds
; <<>> DiG 9.18.39-0ubuntu0.24.04.2-Ubuntu <<>> ds example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 25251
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: 4213d24a5e7680e001000000695288184a3f56087846c871 (good)
;; QUESTION SECTION:
;example.com. IN DS
;; ANSWER SECTION:
example.com. 86400 IN DS 370 13 2 BE74359954660069D5C63D200C39F5603827D7DD02B56F120EE9F3A8 6764247C
;; Query time: 15 msec
;; SERVER: ::1#53(localhost) (UDP)
;; WHEN: Mon Dec 29 22:54:32 JST 2025
;; MSG SIZE rcvd: 164
このように表示されると思います。この場合はキータグが370,アルゴリズムが13,ダイジェストタイプが2,その後の文字列がダイジェストです。ダイジェストが途中でスペースが入っていますがレジストラに登録する際はこのスペースを消してください。レジストラにDSレコードが登録できたらDNSが反映されるまで待ちましょう。基本はすぐに反映されることが多いですが,10分から1時間ほど置いてからdig +dnssec example.com. a @1.1.1.1などのように実行してstatus: SERVFAILではなくstatus: NOERRORと表示されるか確かめましょう。
インラインサイニングを有効にした後に,named.serviceを再起動すると新たにdb.example.com.signedなどのようなファイルが生成されますがこれはBIND9が自動で生成したものなので触らないようにしましょう。編集していいのはdb.example.comだけです。
また,ゾーンファイルを編集し,DNSレコードを追加した場合はシリアル番号を増やしてrndc reloadをする必要があります。ただ一々このコマンドを実行するのは面倒だと思うのでcrontabにスクリプトを実行させるようにする方が楽です。下記にスクリプトの例を載せとくので参考にしてください。もっといい書き方はあると思いますが私には最適化の仕方が分からないので諦めてます。動けばいいやって思ってるので。example.comになってるところとvar/lib/bind/db.example.comになってるところはそれぞれの環境にあったものに変更してください。
#!/bin/bash
TARGETS=(
"example.com:/var/lib/bind/db.example.com"
)
STATE_DIR="/var/lib/bind/zone_watcher_state"
mkdir -p "$STATE_DIR"
chown bind:bind "$STATE_DIR" 2>/dev/null
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') [ZoneWatcher] $1"
}
for TARGET in "${TARGETS[@]}"; do
ZONE_NAME="${TARGET%%:*}"
STATE_FILE="$STATE_DIR/${ZONE_NAME}.hash"
if [ ! -f "$ZONE_FILE" ]; then
log "Error: Zone file for $ZONE_NAME not found at $ZONE_FILE"
continue
fi
CURRENT_HASH=$(md5sum "$ZONE_FILE" | awk '{print $1}')
if [ -f "$STATE_FILE" ]; then
LAST_HASH=$(cat "$STATE_FILE")
else
LAST_HASH=""
fi
if [ "$CURRENT_HASH" != "$LAST_HASH" ]; then
log "Change detected in $ZONE_NAME ($ZONE_FILE)."
CURRENT_SERIAL_VAL=$(named-checkzone -t SOA -i local "$ZONE_NAME" "$ZONE_FILE" 2>/dev/null | grep "SOA" | grep -oE '[0-9]{10}' | head -1)
if [ -n "$CURRENT_SERIAL_VAL" ]; then
TODAY=$(date +%Y%m%d)
SERIAL_DATE=${CURRENT_SERIAL_VAL:0:8}
SERIAL_NUM=${CURRENT_SERIAL_VAL:8:2}
if [ "$SERIAL_DATE" == "$TODAY" ]; then
NEW_SERIAL="${TODAY}$(printf "%02d" $NEW_NUM)"
else
NEW_SERIAL="${TODAY}01"
fi
if [ "$CURRENT_SERIAL_VAL" != "$NEW_SERIAL" ]; then
log "Auto-updating serial: $CURRENT_SERIAL_VAL -> $NEW_SERIAL"
cp "$ZONE_FILE" "$ZONE_FILE.bak"
MARKER_KEY="zone_watcher_id"
if grep -q "; $MARKER_KEY:" "$ZONE_FILE"; then
sed -i "/; $MARKER_KEY:/s/[0-9]\{10\}/$NEW_SERIAL/" "$ZONE_FILE"
log "Updated serial using unique marker line."
else
RAND_ID=$(date +%s%N | sha256sum | head -c 8)
MARKER="; $MARKER_KEY:$RAND_ID"
sed -i "0,/$CURRENT_SERIAL_VAL/s//$NEW_SERIAL $MARKER/" "$ZONE_FILE"
log "Updated serial and added unique marker ($MARKER)."
fi
CURRENT_HASH=$(md5sum "$ZONE_FILE" | awk '{print $1}')
else
log "Serial is already up to date ($NEW_SERIAL)."
fi
else
log "Warning: Could not parse current serial number. Skipping auto-update."
fi
CHECK_OUT=$(named-checkzone -i local "$ZONE_NAME" "$ZONE_FILE" 2>&1)
if [ $? -eq 0 ]; then
log "Syntax check OK. Reloading zone..."
RNDC_OUT=$(rndc reload "$ZONE_NAME" 2>&1)
if [ $? -eq 0 ]; then
log "Reload successful: $RNDC_OUT"
echo "$CURRENT_HASH" > "$STATE_FILE"
else
log "Error: rndc reload failed. $RNDC_OUT"
fi
else
log "Error: Syntax check failed for $ZONE_NAME. Skipping reload."
log "$CHECK_OUT"
fi
fi
done
$ sudo chmod +x /var/lib/bind/zone-update.sh
あとはrootのcrontabに登録しとけばOKです。一度だけ手動で実行し,その後はcrontabに5分毎に実行するようにしておけば問題ないかと思います。仕組みとしてはゾーンファイルの編集を検知したらシリアル番号を増やしてrndc reloadを勝手に実行してDNSレコードの更新を反映させます。ゾーンファイルの編集を検知しなかった場合は動かないようになっています。リソースの無駄な消費を抑えるためですね。
では,crontabに登録していきます。crontabの書き方は調べたらいくらでも出てくるのでここで説明はしません。sudo crontab -e -u rootを実行します。
0 5 1 */3 * certbot certonly --webroot -d ns1.example.com -d ns2.example.com --deploy-hook "systemctl restart named.service"
5 * * * * bash /var/lib/bind/zone-update.sh
1行目はTLS証明書の自動更新,2行目が上記のスクリプトの自動実行です。DoHやDoTを設定している場合は1行目を設定しておくべきでしょう。間違いなく手作業で証明書更新するのは手間ですからね。DNSSECが正しく設定できているかは https://dnsviz.net/ から確認してみてください。問題があればどの部分が問題かを表示してくれます。問題がなければ問題ないと表示してくれます。
おわりに
DNSサーバーを自前で構築するのは大学の授業で初めてやったのですが,その時に面白いなと思って今でも自宅ではDNSサーバーの構築をしてます。流石にオープンリゾルバーは怖過ぎてやってられないですね。自宅ネットワーク内(フレッツの/56と192.168.1.0/24)だけオープンリゾルバーとして扱えるように設定してます。オープンリゾルバーの運用も今後はやってみたいですね。ただ,それは自宅のネットワークと隔離した環境でやりたいのでクラウドサービスあたりを借りてやるのがいいんでしょうかね?Oracle Cloud InfrastructureのArmインスタンスを使ってるんですが,これをオープンリゾルバーにしてみてもいいかもしれません。月10TBまで転送容量(Bandwith)が無料ですし,超えたとしてもネットワーク料金安いですからね。
私はドメインを3つ所有していてそのうちの2つはCloudflare CDNを通しているわけですが,そちらのDNSSECの対応はとても簡単だったんですよ。問題は自宅で運用してる方の権威DNSでのDNSSECの設定なんですよね。なんかマジでシリアル番号あたりの設定とかと絡むとDNSSECでの鍵連鎖が崩れるのか知りませんが,オープンリゾルバーでの名前解決時にエラーが発生したりしてめっちゃ大変でした。下手にゾーンファイルを触るのは良くないことだけは分かりましたね。あと,DNSSECって色々問題あってサブドメイン全て列挙される危険性があるそうです。DNS関連はまだまだ勉強中で知らないことも多くてこんなとんでもない問題もあるんだなぁって調べて知りました。あと実は過去にRFC2136とBIND9を掛け合わせてDNS01-ChallengeによるLet's Encryptでワイルドカード証明書を取得しようとしたことがあるんですが全部ことごとく失敗したんですよね...。マジで難し過ぎる...。やる時は_acme-challenge.example.comっていうサブドメインを別のゾーンファイルで管理してLet's Encryptがこの別管理のゾーンファイルを操作できるようにすることで出来るようになるらしいんですが,なんか上手くできなかったんですよね。どんなエラーが出て無理だったかは忘れましたが。下手に自前の環境でやるよりも安定した確実なCloudflareなどに通してやった方が良いという知見だけは得れましたねw(じゃぁ何故こんな記事書いた...?)。でも,やりがいはあったので今後も色々なものを触ってみたいですね。コンテナー(Docker,Podman,K8Sなど)とかKVMとかを触ったことが全くなくてここら辺を勉強しないとなぁと思いつつ時間がなくて全然手を出せてないんですよね。Linuxだとコンテナーはカーネル上でネイティブ動作するのでパフォーマンスが良いことは知っているんですけど,WindowsだとHyper-V上で,macOSだとLinux VM上で動くらしいですからここが個人的には謎だなぁって思ってます。
今年最後の記事だと思います。実は1年以上編集放棄してる公開済みの記事の下書きがあってやる気が迷子なので数ヶ月は記事書かない気がしますw。