はじめに
自宅ネットワーク環境における名前解決のために、2台構成で冗長化したDNSサーバーを構築してみたのでその手順を解説します。
この構成では、DNSキャッシュサーバーとしてUnboundを動作させ、Keepalivedを使ってVIP(仮想IPアドレス)を割り当てることで冗長化を図ります。
まず、VIPを2つ利用して通常時は各サーバーに別々のVIPが割り当てられるようにしておきます。
もし片方のサーバーが落ちたら、Keepalivedによって自動的にもう片側のサーバーに両方のVIPが割り当てられます。
これらのVIPをネットワーク機器のプライマリーDNSとセカンダリーDNSにそれぞれ指定することで、一方のサーバーで障害が発生した際には全DNSクエリがもう片側のサーバーだけに行くようになる仕組みになります。
システム構成
- 仮想マシン:2台(別物理ホスト上)
- DNSサーバー1(dns1):192.168.40.20
- DNSサーバー2(dns2):192.168.40.21
- OS:Ubuntu Server 24.04 LTS
- ソフトウェア
- Unbound (DNS キャッシュサーバー)
- Keepalived (VRRPによる冗長化ソフト)
- VIP(仮想IPアドレス)
- VIP1(プライマリーDNS用):192.168.40.30
- VIP2(セカンダリーDNS用):192.168.40.31
ソフトウェアのインストール
両サーバーに必要なパッケージをインストールします。
sudo apt install unbound keepalived
Unboundの設定
- ポート53を利用しているsystemd-resolvedを無効化します。
sudo systemctl disable --now systemd-resolved
- /etc/unbound/unbound.conf.d/以下にUnboundの設定ファイルを作成します。今回は管理を容易にするため、設定ファイルを分割しています。
server: interface: 0.0.0.0 interface-automatic: yes # VIPを使うためには必要 port: 53 # ログ設定 verbosity: 1 log-local-actions: yes log-queries: yes log-servfail: yes tls-system-cert: yes # DNS over TLSのドメイン名検証に必要 access-control: 127.0.0.0/8 allow access-control: ::1 allow access-control: 192.168.40.0/24 allow # ローカルネットワークからのアクセスを許可
/etc/unbound/unbound.conf.d/custom_server.conf全ての名前解決の転送先として、Cloudflareが提供しているDNS(1.1.1.1)を指定します。接続にDNS over TLSを利用するため、
forward-tls-upstream
オプションを指定します。forward-zone: name: "." forward-tls-upstream: yes # DNS over TLSを有効化 forward-addr: 1.1.1.1@853#cloudflare-dns.com forward-addr: 1.0.0.1@853#cloudflare-dns.com
/etc/unbound/unbound.conf.d/custom_forward_zone.conf - 必要に応じて内部向けのDNSレコードを追加します。(
.home
をローカルドメインとして想定)server: local-zone: "home." static # A レコード local-data: "srv1.home. A 192.168.40.10" local-data: "srv2.home. A 192.168.40.11" local-data: "dns1.home. A 192.168.40.20" local-data: "dns2.home. A 192.168.40.21" # PTR レコード local-data-ptr: "192.168.40.10 srv1.home." local-data-ptr: "192.168.40.11 srv2.home." local-data-ptr: "192.168.40.20 dns1.home." local-data-ptr: "192.168.40.21 dns2.home."
- Unboundサービスを有効化します。
sudo systemctl enable unbound sudo systemctl restart unbound
Keepalivedの設定
Keepalivedの設定では、VIPに対する優先度を各サーバーで入れ替えて設定します。
VIP1 優先度 | VIP2 優先度 | |
---|---|---|
dns1 | 110 | 90 |
dns2 | 90 | 110 |
通常時割当 | dns1 | dns2 |
この設定により、両方のサーバーが動いているときには通常時はVIP1がdns1に、VIP2がdns2に割り当てられます。いずれかのサーバーがダウンした場合には、もう一方のサーバーが両方のVIPを引き継ぎます。これによってActive/Active構成の冗長化を実現します。
認証パスワードの作成
認証用のパスワードとしてランダムな文字列(8文字以内)を作成します。作成したら両サーバーの設定ファイルに記載してください。
dns1サーバーの設定
Unboundの設定は次のようにします。
global_defs {
vrrp_garp_master_refresh 60
enable_script_security
script_user root
}
vrrp_script track_unbound {
script "/usr/bin/systemctl is-active unbound.service"
interval 5
fall 3
rise 2
}
vrrp_instance VIP_1 {
state BACKUP
interface eth0 # インターフェースを指定
virtual_router_id 10
priority 110
advert_int 1
authentication {
auth_type AH
auth_pass <認証パスワード>
}
virtual_ipaddress {
192.168.40.30/24 # VIP1のアドレス
}
track_script {
track_unbound
}
}
vrrp_instance VIP_2 {
state BACKUP
interface eth0 # インターフェースを指定
virtual_router_id 20
priority 90
advert_int 1
authentication {
auth_type AH
auth_pass <認証パスワード>
}
virtual_ipaddress {
192.168.40.31/24 # VIP2のアドレス
}
track_script {
track_unbound
}
}
dns2サーバーの設定
priority以外はdns1と一緒です。
global_defs {
vrrp_garp_master_refresh 60
enable_script_security
script_user root
}
vrrp_script track_unbound {
script "/usr/bin/systemctl is-active unbound.service"
interval 5
fall 3
rise 2
}
vrrp_instance VIP_1 {
state BACKUP
interface eth0 # インターフェースを指定
virtual_router_id 10
priority 90
advert_int 1
authentication {
auth_type AH
auth_pass <認証パスワード>
}
virtual_ipaddress {
192.168.40.30/24 # VIP1のアドレス
}
track_script {
track_unbound
}
}
vrrp_instance VIP_2 {
state BACKUP
interface eth0 # インターフェースを指定
virtual_router_id 20
priority 110
advert_int 1
authentication {
auth_type AH
auth_pass <認証パスワード>
}
virtual_ipaddress {
192.168.40.31/24 # VIP2のアドレス
}
track_script {
track_unbound
}
}
Keepalivedの有効化
両サーバーで実行します。
sudo systemctl enable keepalived
sudo systemctl restart keepalived
動作確認手順
- サービス状態の確認
起動に失敗していたら設定ファイルのミスを確認してください。
sudo systemctl status unbound sudo systemctl status keepalived
- VIP割り当ての確認
$ ip a ... inet 192.168.40.30/24 scope global secondary eth0
- 名前解決の確認(別マシンから実施)
dig @192.168.40.30 google.com +short dig @192.168.40.31 srv1.home +short
別マシン上 - 冗長化の確認
- 片方のサーバーでUnboundをダウンしてみます。
sudo systemctl stop unbound
dns1上 - もう一方のサーバーに両方のVIPが割り当てられていることを確認します。
$ journalctl -xe -u keepalived ... Dec 22 00:00:10 dns1 Keepalived_vrrp[00000]: (VIP_1) Entering MASTER STATE
dns2上(ログの確認)$ ip a ... inet 192.168.40.30/24 scope global secondary eth0 ... inet 192.168.40.31/24 scope global secondary eth0
dns2上(インターフェースの確認) - Unboundを起動し直してVIPが再度両サーバーに分配されることを確認します。
sudo systemctl start unbound
dns1上$ journalctl -xe -u keepalived ... Dec 22 00:10:10 dns2 Keepalived_vrrp[00000]: (VIP_1) Master received advert from 192.168.40.20 with higher priority 110, ours 90 Dec 22 00:10:10 dns2 Keepalived_vrrp[00000]: (VIP_1) Entering BACKUP STATE
dns2上(ログの確認)
- 片方のサーバーでUnboundをダウンしてみます。
まとめ
本記事ではUnboundとKeepalivedを利用して冗長化されたDNSサーバーを構築する手順を解説しました。
構築したDNSサーバーのVIP2つをそれぞれルーターやPCのプライマリー/セカンダリーDNSに設定することで、比較的障害に強いローカルDNS環境が実現できるはずです。