はじめに

この記事では、Rocky Linux 9 上に PowerDNS のパッケージ群を使って自宅用の DNS サーバを構築する手順を記載する。

自宅DNSサーバ構成

この記事では、下記のような構成で構築する。

項目 設定
ハードウェア Proxmox VE が構築済みの仮想環境
OS Rocky Linux 9 (LXC コンテナ)
メモリ 2GB
ストレージ 20GB
DNS 権威サーバ PowerDNS Authoritative Server
DNS リゾルバ PowerDNS Recursor
DNS プロキシ&ロードバランサー PowerDNS DNSdist
DNS バックエンド DB MariaDB
DNS 権威サーバ用 WebUI PowerDNS-Admin (Docker)

DNS サーバ構成図

自宅DNSサーバ構成図

構築手順

設定パラメータ

各サーバの設定値を先にまとめておく。記事内のスクリプトの値を、各自の環境に合わせて書き換えること。

システム 項目 設定
DNSサーバ ホスト名 dns01
DNSサーバ IPv4 アドレス 192.0.2.50/24
DNSサーバ IPv4 デフォルトゲートウェイ 192.0.2.1
DNSサーバ IPv6 アドレス 2001:DB8::32/64
DNSサーバ IPv6 デフォルトゲートウェイ 2001:DB8::1/64
DNSサーバ 上位DNSフォワード先アドレス 1.1.1.1
1.0.0.1
2606:4700:4700::1111
2606:4700:4700::1001
MariaDB バージョン 11.4 (LTS)
MariaDB root パスワード 6g8nS9QSC5HDhdbx
MariaDB pdnsadmin ユーザーパスワード 3mwH1QeuiMV53157
PowerDNS DNSdist バージョン 1.9.8
PowerDNS DNSdist Listen Port UDP/TCP 53
PowerDNS DNSdist Web UI password 36J55V7jUk0D
PowerDNS DNSdist Web API Key ab164a08-1775-4dff-a633-4a9b542605e2
PowerDNS Authoritative Server バージョン 4.9
PowerDNS Authoritative Server DNS Listen Port UDP/TCP 25301
PowerDNS Authoritative Server API KEY faa5b1ce-1495-4fce-9129-735078a675f2
PowerDNS Authoritative Server API Listen port 8081
PowerDNS Recursor バージョン 5.1
PowerDNS Recursor Listen Port UDP/TCP 25302
PowerDNS-Admin バージョン 0.4.2
PowerDNS-Admin Listen Port TCP 9191
DNSゾーン ゾーン名 home
DNSゾーン IPv4 セグメント 192.0.2.0/24
DNSゾーン IPv6 セグメント 2001:DB8::/64
  • IPv4 / IPv6 アドレスは、それぞれ RFC 5737 / RFC 3849 に従って例示用アドレスを記載
  • パスワードは develop.tools | パスワード生成ツール で作成
  • API キーは develop.tools | UUID生成ツール で作成
  • 「上位DNSフォワード先アドレス」はプロバイダ提供の IP アドレス、または Public DNS を指定
    • 例では Cloudflare の IPv4/IPv6 アドレスを指定している

MariaDB インストール

dnf リポジトリ設定

MariaDB 11.4 LTS版 の例

MARIADBVERSION=11.4
cat <<__EOT__> /etc/yum.repos.d/mariadb.repo
[mariadb]
name = MariaDB
baseurl = https://rpm.mariadb.org/${MARIADBVERSION}/rhel/\$releasever/\$basearch
gpgkey= https://rpm.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1
__EOT__

インストール

dnf install -y MariaDB-server
systemctl enable mariadb
systemctl start mariadb

MariaDB 初期設定

初期セキュリティ設定値

mariadb-secure-installation

Enter current password for root (enter for none): [Enter]
Switch to unix_socket authentication [Y/n] y[Enter]
Change the root password? [Y/n] y[Enter] 6g8nS9QSC5HDhdbx
6g8nS9QSC5HDhdbx
(MariaDB の root ユーザーのパスワードを2回入力)
Remove anonymous users? [Y/n] y[Enter]
Disallow root login remotely? [Y/n] y[Enter]
Remove test database and access to it? [Y/n] y[Enter]
Reload privilege tables now? [Y/n] y[Enter]

ログ設定変更

/etc/my.cnf.d/server.conf 内 vi で編集 ※デフォルトだと警告メッセージが出すぎるため

[mysqld]
log_warnings = 1

MariaDB 初回ログイン

パスワードを聞かれるので、設定したパスワードでログイン

# mariadb -u root -p
Enter password: 6g8nS9QSC5HDhdbx[Enter]
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 2397
Server version: 11.4.4-MariaDB MariaDB Server

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> 

PowerDNS 用のユーザーを設定

CREATE DATABASE pdns;
GRANT ALL ON pdns.* TO pdnsadmin@localhost IDENTIFIED BY '3mwH1QeuiMV53157';
FLUSH PRIVILEGES;

設定確認

SHOW GRANTS FOR pdnsadmin@localhost;

下記の中身が表示されればOK

Grants for pdnsadmin@localhost

[Ctrl]-[D] で抜ける

PowerDNS パッケージ群インストール

レポジトリセットアップ

参考: https://repo.powerdns.com/

PowerDNS Authority 4.9 / PowerDNS Recursor 5.1 / dnsdist 1.9 の例

PDNS_AUTH_VER=49
PDNS_RECURSOR_VER=51
PDNS_DNSDIST_VER=19
curl -o /etc/yum.repos.d/powerdns-auth-${PDNS_AUTH_VER}.repo https://repo.powerdns.com/repo-files/el-auth-${PDNS_AUTH_VER}.repo
curl -o /etc/yum.repos.d/powerdns-rec-${PDNS_RECURSOR_VER}.repo https://repo.powerdns.com/repo-files/el-rec-${PDNS_RECURSOR_VER}.repo
curl -o /etc/yum.repos.d/powerdns-dnsdist-${PDNS_DNSDIST_VER}.repo https://repo.powerdns.com/repo-files/el-dnsdist-${PDNS_DNSDIST_VER}.repo

パッケージインストール

dnf install -y pdns pdns-backend-mysql pdns-recursor dnsdist

PowerDNS 用に MariaDB セットアップ

DBのパスワードを聞かれたら入力

mariadb -u pdnsadmin -p pdns < /usr/share/doc/pdns-backend-mysql/schema.mysql.sql
XXXXXXXXXXXX

PowerDNS Auth (Authoritative Server) / Recursor 設定

PDNS Auth オリジナル設定バックアップ

cp -a /etc/pdns/pdns.conf /etc/pdns/pdns.conf.DEFAULT
PDNS_AUTH_BASE='/etc/pdns'
PDNS_RECURSOR_BASE='/etc/pdns-recursor'
# UUID生成ツール等で作成
PDNS_AUTH_APIKEY='faa5b1ce-1495-4fce-9129-735078a675f2'
MARIADB_PASSWORD='3mwH1QeuiMV53157'
# CloudFlare の場合
UPSTREAM_DNS_IPv4_1=1.1.1.1
UPSTREAM_DNS_IPv4_2=1.0.0.1
UPSTREAM_DNS_IPv6_1=2606:4700:4700::1111
UPSTREAM_DNS_IPv6_2=2606:4700:4700::1001

# PDNS Auth config
cat <<__EOT__ >${PDNS_AUTH_BASE}/pdns.conf
api=yes
api-key=${PDNS_AUTH_APIKEY}
webserver=yes
webserver-address=0.0.0.0
webserver-allow-from=127.0.0.0/8
webserver-port=8081
launch=gmysql
gmysql-socket=/var/lib/mysql/mysql.sock
gmysql-user=pdnsadmin
gmysql-password=${MARIADB_PASSWORD}
gmysql-dbname=pdns
local-address=127.0.0.1 ::1
local-port=25301
security-poll-suffix=
setgid=pdns
setuid=pdns
# log-dns-details=yes
# log-dns-queries=yes
log-timestamp=yes
# logging-facility=0
# loglevel=7
dnsupdate=yes
allow-dnsupdate-from="127.0.0.0/8, ::1/128"
__EOT__
chgrp pdns ${PDNS_AUTH_BASE}/pdns.conf
chmod 640 ${PDNS_AUTH_BASE}/pdns.conf

# PDNS Recursor config (YAML形式)
cat <<__EOT__ >${PDNS_RECURSOR_BASE}/recursor.d/recursor.yml
incoming:
  listen:
    - 127.0.0.1
    - ::1
  allow_from:
    - 127.0.0.0/8
    - '::1/128'
  port: 25302
  tcp_fast_open: 100
outgoing:
  tcp_fast_open_connect: true
  source_address: 
    - 0.0.0.0
    - '::'
recursor:
  extended_resolution_errors: true
  serve_rfc1918: false
  hint_file: no-refresh
  forward_zones_recurse:
    - zone: .
      forwarders:
        - ${UPSTREAM_DNS_IPv4_1}
        - ${UPSTREAM_DNS_IPv4_2}
        - ${UPSTREAM_DNS_IPv6_1}
        - ${UPSTREAM_DNS_IPv6_2}
  lua_config_file: ${PDNS_RECURSOR_BASE}/recursor.d/nta.lua
logging:
  # loglevel: 7
  # common_errors: true
  # quiet: false
  timestamp: true
  # trace: false
__EOT__

echo "Creating syslog configuration:"
mkdir -p /var/log/powerdns
chmod a+w /var/log/powerdns
cat <<__EOT__ > /etc/rsyslog.d/powerdns.conf
if ($programname contains 'pdns-recursor') then {
    action(type="omfile" file="/var/log/powerdns/pdns-recursor.log")
}
if ($programname contains 'pdns_server') then {
    action(type="omfile" file="/var/log/powerdns/pdns-auth.log")
}
__EOT__

echo "Creating logrotate configration:"
cat <<__EOT__ > /etc/logrotate.d/powerdns
/var/log/powerdns/*.log
{
    missingok
    sharedscripts
    postrotate
        /usr/bin/systemctl -s HUP kill rsyslog.service >/dev/null 2>&1 || true
    endscript
}
__EOT__

systemctl reload rsyslog.service
systemctl enable pdns-recursor.service
systemctl restart pdns-recursor.service
systemctl enable pdns.service
systemctl restart pdns.service

dnsdist 設定

PDNS dnsdist オリジナル設定バックアップ

mkdir /var/log/dnsdist
cp -a /etc/dnsdist/dnsdist.conf /etc/dnsdist/dnsdist.conf.ORG

web api key の生成

$ dnsdist -l 127.0.0.1:5300 -C /dev/null
> hashPassword('ab164a08-1775-4dff-a633-4a9b542605e2')
$scrypt$ln=10,p=1,r=8$7aMm9zGGfidk3qBQJ5TIgQ==$CAO2O0SnvfHnCKbftNf+qfrar4cgPhB0TREc1p89dHU=

console key の生成

$ dnsdist -l 127.0.0.1:5300 -C /dev/null
> makeKey()
setKey("J7lAScDbcLtFGVtXsZf8eKxWj0/4+4NJ3Mb7BkFseHc=")

サービス設定

# 決めておいた設定パラメータからコピペする
WEBPASSWORD="36J55V7jUk0D"
# 上記 dnsdist 内で生成した値をコピペする
WEBAPIKEY='$scrypt$ln=10,p=1,r=8$7aMm9zGGfidk3qBQJ5TIgQ==$CAO2O0SnvfHnCKbftNf+qfrar4cgPhB0TREc1p89dHU='
# 上記 dnsdist 内で生成した値をコピペする
CONSOLEKEY='J7lAScDbcLtFGVtXsZf8eKxWj0/4+4NJ3Mb7BkFseHc='
LOCALIP='192.0.2.50'
LOCALSEGMENTV4='192.0.2.0/24'
LOCALSEGMENTV6='2001:DB8::/64'
FORWARD_ZONE="home"
PTR_ZONE="2.0.192.in-addr.arpa"

cat <<__EOT__ > /etc/dnsdist/dnsdist.conf
-- disable security status polling via DNS, we know we're EOL
setSecurityPollSuffix('')

-- Set Netmask Group
-- https://dnsdist.org/reference/netmaskgroup.html
allowQueryAddresses = newNMG()
allowQueryAddresses:addMask('127.0.0.0/8')
allowQueryAddresses:addMask('::1/128')
allowQueryAddresses:addMask('fe80::/64')
allowQueryAddresses:addMask('${LOCALSEGMENTV4}')
allowQueryAddresses:addMask('${LOCALSEGMENTV6}')

allowUpdateAddresses = newNMG()
allowUpdateAddresses:addMask('${LOCALSEGMENTV4}')
allowUpdateAddresses:addMask('${LOCALSEGMENTV6}')

-- ACL of DNS query
-- https://dnsdist.org/advanced/acl.html
setACL('0.0.0.0/0')
addACL('::/0')

-- dnsdistのListenサーバIPアドレス:使用ポート
-- https://dnsdist.org/reference/config.html#listen-sockets
-- https://dnsdist.org/reference/config.html#setLocal
-- https://dnsdist.org/reference/config.html#addLocal
-- set primary listen address
setLocal('0.0.0.0:53')
addLocal('[::]:53')

-- バックエンド: IPアドレス:使用ポート、バックエンド名、秒間クエリ制限数
-- https://dnsdist.org/reference/config.html#newServer
newServer({address='127.0.0.1:25301', name='authoritive', pool={'auth'}})
newServer({address='127.0.0.1:25302', name='recursor', pool={'resolver'}})

-- ロギング設定
-- https://dnsdist.org/reference/actions.html#LogAction
-- LogAction([filename[, binary[, append[, buffered[, verboseOnly[, includeTimestamp]]]]]])
-- クエリのデバッグをする際のみ、下記のコメントを外す
-- addAction(AllRule(), LogAction('/var/log/dnsdist/query.log', false, false, false, true, true))

-- [How to generate key]
-- https://dnsdist.org/guides/console.html
--   dnsdist -l 127.0.0.1:5300 -C /dev/null
--   > makeKey()
setKey('${CONSOLEKEY}')
controlSocket('${LOCALIP}:5199')
setConsoleACL({
    '${LOCALSEGMENTV4}',
    '192.168.2.0/24'
})

-- SuffixMatchNode
-- https://dnsdist.org/reference/config.html#suffixmatchnode
authdomains = newSuffixMatchNode()
authdomains:add(newDNSName('${FORWARD_ZONE}.'))
authdomains:add(newDNSName('${PTR_ZONE}.'))

-- 振り分けルール
-- https://dnsdist.org/reference/rules-management.html
-- https://dnsdist.org/reference/actions.html
addAction(
    SuffixMatchNodeRule(authdomains),
    PoolAction('auth')
)
addAction(
    OpcodeRule(DNSOpcode.Update),
    PoolAction('auth')
)
addAction(
    NetmaskGroupRule(allowQueryAddresses),
    PoolAction('resolver')
)

-- dnsdist dashboard
-- https://dnsdist.org/guides/webserver.html
-- https://dnsdist.org/reference/config.html#webserver
webserver('0.0.0.0:8083')
setWebserverConfig({
    password='${WEBPASSWORD}',
    apikey='${WEBAPIKEY}',
    acl='0.0.0.0/0,::/0'
})
__EOT__
systemctl enable dnsdist.service
systemctl start dnsdist.service

ゾーン登録例

初期登録テスト用として、ゾーン情報を pdnsutil コマンドで登録する。

参考: PowerDNS Manual: pdnsutil

PDNS_RECURSOR_BASE='/etc/pdns-recursor'
ZONE="home"
PTR_ZONE="2.0.192.in-addr.arpa"
SOA_MASTER="dns01.${ZONE}."
SOA_CONTACT="hostmaster.${ZONE}."
SOA_SERIAL=0
SOA_REFRESH=28800 # 8 hours
SOA_RETRY=3600 # 1 hour
SOA_EXPIRE=2419200 # 28 days
SOA_NEGATIVE=900 # 15 minutes
SOA_RECORD="${SOA_MASTER} ${SOA_CONTACT} ${SOA_SERIAL} ${SOA_REFRESH} ${SOA_RETRY} ${SOA_EXPIRE} ${SOA_NEGATIVE}"
RR_TTL=3600 # 1 hour

LOCAL_SEGMENT=""

# clear zone
pdnsutil delete-zone "${ZONE}"
pdnsutil delete-zone "${PTR_ZONE}"

## SAMPLE ZONE ENTRY
# Create Forward lookup zone
pdnsutil create-zone "${ZONE}"
pdnsutil set-kind "${ZONE}" native
pdnsutil replace-rrset "${ZONE}" @ SOA "${SOA_RECORD}"
pdnsutil add-record "${ZONE}" @ NS dns01.${ZONE}.

## DNSサーバ自身の正引き登録
pdnsutil add-record "${ZONE}" dns01 A 192.0.2.50
pdnsutil add-record "${ZONE}" dns01 AAAA '2001:DB8::32'

# Create Reverse lookup zone
pdnsutil create-zone "${PTR_ZONE}" 
pdnsutil set-kind "${PTR_ZONE}" native
pdnsutil replace-rrset "${PTR_ZONE}" @ SOA "${SOA_RECORD}"
pdnsutil add-record "${PTR_ZONE}" @ NS dns01.${ZONE}.

## DNSサーバ自身の逆引き登録
pdnsutil add-record "${PTR_ZONE}" 50 PTR dns01.home.

recursor に NTA を登録

DNSSEC 検証エラーを抑止するため、ローカルゾーンを NTA (Negative Trust Anchor) として登録する。

これを設定しないと名前解決できずに悩む。

cat <<__EOT__ > ${PDNS_RECURSOR_BASE}/recursor.d/nta.lua
addNTA('${ZONE}', 'internal domains')
addNTA('${PTR_ZONE}', 'private ptr zone')
__EOT__
systemctl restart pdns-recursor.service

PowerDNS の WebUI を追加

docker engine 導入

dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
dnf install -y docker-ce docker-compose-plugin
# change bridge network
cat <<'__EOT__' >/etc/docker/daemon.json
{
    "default-address-pools":[  
        {  
            "base":"172.29.0.0/16",
            "size":24
        }
    ]
}
__EOT__
# start dockerd
systemctl enable docker.service
systemctl start docker.service

PowerDNS-Admin 導入 (docker)

作成済みの PowerDNS Authoritative Server 用 API KEY を貼る。

docker run -d \
    -e SECRET_KEY='faa5b1ce-1495-4fce-9129-735078a675f2' \
    -v pda-data:/data \
    -p 9191:80 \
    --restart always \
    powerdnsadmin/pda-legacy:latest

PowerDNS-Admin 初回設定

ブラウザでアクセス http://192.0.2.50:9191/

PowerDNS-Admin ログイン画面

ユーザー登録する

  • Create an account
  • First Name: FIRSTNAME
  • Last Name: LASTNAME
  • Email: [email protected]
  • Username: xxxx
  • Password: XXXXXXXXX

WebUI内で設定
※わかりにくいが、PowerDNS Authoritative Server の IP は、Docker の内部から見たホスト自身になるため、docker0 ブリッジの先頭 IP アドレスを指定する。

  • PowerDNS API URL: http://172.29.0.1:8081/
  • PowerDNS API Key: faa5b1ce-1495-4fce-9129-735078a675f2

設定が完了すると、Web UI からゾーン編集ができるようになる。

PowerDNS-Admin コンソール

起動順序調整

デフォルトだと、再起動時の起動順序で失敗することがあるため、systemd の設定に依存関係を追記する。

/usr/lib/systemd/system/pdns.service に追記

[Unit]
#中略
Wants=mariadb.service
After=mariadb.service

/usr/lib/systemd/system/pdns-recursor.service に追記

[Unit]
#中略
After=pdns.service

/usr/lib/systemd/system/dnsdist.service に追記

[Unit]
#中略
After=pdns.service pdns-recursor.service

systemd に反映

systemctl daemon-reload

動作確認

再起動後のサービス確認

プロセス確認

ps axuw | grep "pdns|dnsdist"

pdns_server, pdns_recursor, dnsdist のプロセスが上がっているか確認。

dnsdist      185  0.1  3.9 2108992 83432 ?       SLsl Jan04  14:28 /usr/bin/dnsdist --supervised --disable-syslog
pdns-re+ 2350190  0.0  1.3 420764 28412 ?        Ssl  18:27   0:07 /usr/sbin/pdns_recursor --daemon=no --write-pid=no --disable-syslog --log-timestamp=no
pdns     2378134  0.0  2.9 677380 62080 ?        SLsl 20:43   0:00 /usr/sbin/pdns_server --guardian=no --daemon=no --disable-syslog --log-timestamp=no --write-pid=no

ログにエラーが出ていないか確認

less /var/pdns-auth.log
less /var/pdns-recursor.log

外部問合せテスト

サーバ上の dig コマンドでテスト。

# dig +noall +ans @localhost blog.yamk.net A
blog.yamk.net.          216     IN      A       172.67.199.171
blog.yamk.net.          216     IN      A       104.21.21.177
# dig +noall +ans @localhost blog.yamk.net AAAA
blog.yamk.net.          300     IN      AAAA    2606:4700:3032::ac43:c7ab
blog.yamk.net.          300     IN      AAAA    2606:4700:3033::6815:15b1

内部問合せテスト

# dig +noall +ans @localhost dns01.home A
dns01.home.             3600    IN      A       192.0.2.50
# dig +noall +ans @localhost dns01.home AAAA
dns01.home.             3600    IN      AAAA    2001:DB8::32

逆引きも試す。

# dig +noall +ans @localhost -x 192.168.0.24
24.0.168.192.in-addr.arpa. 3600 IN      PTR     dns01.home.

PC端末から問合せテスト

PC端末の Windows PowerShell から、DNS サーバを指定して問い合わせてみる。
Resolve-DnsName コマンドレットでは -Type A_AAAA オプションで IPv4 と IPv6 アドレスを同時にクエリできる。

外部ホスト

Resolve-DnsName -Name blog.yamk.net -Server 192.0.2.50 -Type A_AAAA
Name              Type   TTL   Section    IPAddress
----              ----   ---   -------    ---------
blog.yamk.net     AAAA   176   Answer     2606:4700:3033::6815:15b1
blog.yamk.net     AAAA   176   Answer     2606:4700:3032::ac43:c7ab
blog.yamk.net     A      99    Answer     172.67.199.171
blog.yamk.net     A      99    Answer     104.21.21.177

内部ホスト正引き

Resolve-DnsName -Name dns01.home -Server 192.0.2.50 -Type A_AAAA
Name              Type   TTL   Section    IPAddress
----              ----   ---   -------    ---------
dns01.home        AAAA   3600  Answer     2001:DB8::32
dns01.home        A      3600  Answer     192.0.2.50

内部ホスト逆引き

Resolve-DnsName -Name 192.168.0.24 -Server 192.168.0.24 -Type PTR
Name                        Type   TTL   Section    NameHost
----                        ----   ---   -------    --------
50.2.0.192.in-addr.arpa     PTR    3600  Answer     dns01.home

仕上げ

もろもろテストして問題なさそうなら、家庭内 LAN の DHCP サーバで配布している DNS サーバのアドレスを、上で構築した DNS サーバに変更する。念のため、フォールバック先として元の DNS サーバも残しておく。

例:

  • プライマリ DNS サーバ: 192.0.2.50 ※新規構築した DNS
  • セカンダリ DNS サーバ: 192.0.2.1 ※元々の DNS サーバ(ブロードバンドルータなど)

各端末の参照先が新規 DNS サーバに向いたら、さらにテストを繰り返して安定性を確認する。

以上。

余談

ブロードバンドルータやホームゲートウェイ内蔵の DNS 機能ではなく、敢えて独立 DNS サーバを用意することで ネットが快適になる。構築リソースとか維持コスト等の状況が許すなら自宅 DNS 構築はお勧めである。自力で構築したからといって、すべてが解決するわけではないが、得るものは必ずある。

ただし DNS の知識はそれなりに必要なので、中途半端な運用で上位 ISP に迷惑を掛けないよう心がけたい。

「自宅 DNS」の2つの意味

自宅 (または小規模の事務所など) の DNS として求められているものは、主に2つある。

(1) 外部インターネットアクセス用の DNS

Webサイト閲覧や各種動画アプリ、ネットワークゲーム、オンラインサービス等で、外部へアクセスするときは必ず DNS が使用される。

PC やスマホ端末から現代的な Web サイトを見る場合、1回のアクセスでも Javascript やフォントダウンロード・アクセス解析・広告など、多数のサイトに横断して複雑な送受信が走る。

一方、近年普及してきた Akamai や Cloudflare に代表される CDN (コンテンツデリバリネットワーク) は、

  • 世界中に多数のコンテンツサーバが配置され
  • 問い合わせるたびにホスト IP が変わる (冗長化+ネットワーク距離最適化)

という特徴があるため、DNS キャッシュ保持時間が短く設定されている。すなわち、同じ URL へのアクセスでも頻繁に DNS リクエストが発生する。

DNS キャッシュとか DNS プロキシといった機能は、ブロードバンドルータや ISP が提供するホームゲートウェイも内蔵されている。ただし制御範囲が狭く、大抵「名前解決のパフォーマンス」もそれなりであるため、DNS の応答速度向上は体感に影響する。

また IPv6 の普及により応答データ量が DNS 当初の仕様 (512バイト) を越えることも多くなったため、レスポンスが落ちる TCP フォールバックではなく、EDNS0 によるメッセージサイズ拡張 に対応していてほしい。

ブロードバンドルータの DNS の不具合で、インターネットアクセスが不安定になってしまった事例もある。

(2) ローカルサーバ用の DNS

Linux サーバを複数立て始めると、欲しくなってくるのが内部ホスト名でのアクセスである。

古くは NBT (NetBIOS over TCP/IP), Apple の Bonjour, LLMNR, 最近では mDNS といった 同じセグメント内で自動的にホスト名とIPアドレスを紐づけるといった技術 は存在するが、ブロードキャストやマルチキャストが届く範囲でしか名前解決できないため、セグメントを分けた瞬間にホスト名が見えなくなってしまう。

自分の場合、仮想環境内に仮想ルータを立ててセグメントを分けたり、外部から OpenVPN で自宅 LAN に入ってきたりしているので、分かりやすいホスト名でアクセスできるようにしておきたい。

「ホスト名+ドメイン」と「IPアドレス」を直接紐づけるサーバを 権威サーバ (Authoritative Server) と呼び、ブロードバンドルーター・ホームゲートウェイにも簡易版がついていることもあるが、あまり使いやすくはない。

自宅ネットワーク内の各種ホスト名は変化するので、Web 管理画面等でメンテナンスしやすくしておきたい。

PowerDNS 所感

  • PowerDNS Recursor は設定ファイルが YAML に移行したが、Authoritative Server は従来のまま。
  • PowerDNS Dist に至っては Lua 形式で超わかりにくい。
  • 性能はともかく、同じブランドであれば設定方法も統一してほしい‥‥。
  • キャッシュ DNS 性能だけなら Unbound の方がよさそう。

残テーマ

  • Kea DHCP で自宅内 DHCP サーバ
    • もうブロードバンドルータなんてファイアウォールと NAT だけで十分
    • Kea DHCP の日本語記事が少ない上にいろいろ仕様変更が
  • Kea DHCP サーバと連動して、動的ホスト名登録を DNS へ登録
    • できそうだが未確認

参考