BINDでダイナミックDNSを作る

Docker

小さなオフィスでも複数のサーバーがあるなら、「ipアドレス」ではなく「ホスト名」でアクセスしたいと思うでしょう。

以前このサイトでDockerコンテナを使ってDNSキャッシュサーバーを作りました。

これをグレードアップして、ネットワーク内のコンピュータを動的に登録します。

更新頻度が少ない場合は、DDNSにせず、ゾーンファイルを都度編集したほうが早いかもしれません。

しかしDDNSであれば、手元のPCからアップデートが可能ですし、間違うリスクが減ります。

注意が必要なのは、このDNSサーバーは、プライベートネットワークで便利に使うためのもので、決してインターネットに公開してはいけないものです。

グローバルネットワークに公開するDNSは、セキュリティーから考えなければいけないからです。

ゾーン名を決める

まず、事務所内や家庭内のネットワークの「ゾーン名(ドメイン名)」を決めます。

インターネットの公式のドメインをもっているなら、それを使ってもいいし、ローカル専用に新規作成してもいいでしょう。

「localnet」でもいいのですが、この単語はいろんなところに使われていて紛らわしいので止めておきます。

ここでは例としてゾーン名を「yellow.in.net」としました。

従って、これから設定するDNSサーバー「dns0」の正式なホスト名は「 dns0.yellow.in.net 」です。

ゾーンファイルを作る

「/etc/bind/」に「db.empty」という空のゾーンファイルがあるので、これをコピーして使います。

cp /etc/bind/db.empty /etc/bind/db.yellow.in.net

コピーした「db.yellow.in.net」を次のように編集します。

「;」より右側はコメントとして扱われます。

; BIND reverse data file for empty rfc1918 zone
;
; DO NOT EDIT THIS FILE - it is used for multiple zones.
; Instead, copy it, edit named.conf, and use that copy.
;
$TTL	86400
@	IN	SOA	dns0.yellow.in.net. fumi.yellow.in.net. (
			      1		; Serial
			 604800		; Refresh
			  86400		; Retry
			2419200		; Expire
			  86400 )	; Negative Cache TTL
;
@	IN	NS	dns0.yellow.in.net.
dns0    IN       A      192.168.11.2

最初の「 $TTL 86400 」は、キャッシュサーバーがこのゾーンの検索結果を保持する期間です。

1度問い合わせたに答えたらキャッシュサーバーのほうでその情報を覚えておいて、86400秒、すなわち1日の間は再び問合せしないように要請します。

「db.empty」の「SOA」の行を、自分の環境に合わせて書き換えます。

「db.empty」の 「SOA」レコード:

@       IN      SOA     localhost. root.localhost. (

変更後の「SOA」レコード:

@	IN	SOA	dns0.yellow.in.net. fumi.yellow.in.net. (

この意味は次のようになります。

要素意味
@ゾーン名、つまり「yellow.in.net」に置き換えられます。
INインターネットのことです。「IN」以外を使うことはありません。
SOA「Start Of Authority」の略で、権威を持つゾーンの始まりを意味します。
dns0.yellow.in.net. このゾーンの情報を管理している権威サーバー名。
fumi.yellow.in.net. 管理者のメールアドレス。

dns0.yellow.in.netではなく「 dns0.yellow.in.net. 」で最後の「.」を忘れないでください。

メールアドレスは「 fumi@yellow.in.net」と書かずに、最後の「.」もつけて「 fumi.yellow.in.net. 」と書きます。

続く「丸カッコ」に囲まれた5個の数字は次のような意味を持っています。

要素コメント期間意味誰に対するものか
1 Serial数字が大きいほど新しいセカンダリーサーバー
604800 Refresh7日セカンダリー サーバーが更新を確認する間隔セカンダリーサーバー
86400 Retry1日リフレッシュできなかった場合に、
再度更新を確認するまでの間隔
セカンダリーサーバー
2419200 Expire28日更新ができなかったときに現在の情報を
保持する期間
セカンダリーサーバー
86400 Negative Cache TTL1日問い合わせ先が存在しなかった場合、
「存在しない」ことを保持しておく期間
キャッシュサーバー

次に権威サーバーについての情報を2行記述します。

@	IN	NS	dns0.yellow.in.net.
dns0    IN       A      192.168.11.2

この意味は以下の通りです。

意味
NSNSレコードネームサーバー
AAレコードアドレス

「@」はゾーン名(ドメイン名)に変換されます。

@	IN	NS	dns0.yellow.in.net.

ゾーン「yellow.in.net」のネームサーバーは「dns0.yellow.in.net」です。

dns0    IN       A      192.168.11.2

「dns0.yellow.in.net」 のアドレスは「192.168.11.2」です。

サーバー名はゾーン名(ドメイン名)を省略して記述することができ「dns0」と書くことができます。

ゾーン名を省略しないで書くときは次のようになります。

dns0.yellow.in.net.    IN       A      192.168.11.2

ホスト名の最後の「.」を忘れて、次のようにしないでください。

dns0.yellow.in.net    IN       A      192.168.11.2

これは「dns0.yellow.in.net.yellow.in.net」 のアドレスは「192.168.11.2」の意味になります。

ゾーンファイルは以上です。

「SOA」の情報だけを設定しておけば、後は動的に登録できます。

allow-updateでDDNSに変身させる

ゾーンファイルができたので、ゾーンを有効にします。

BINDの設定ファイルは、「/etc/bind/named.conf」です。

Debianでは、 named.confから以下のファイルをインクルード(読み込む)するようになっています。

  • /etc/bind/named.conf.options
  • /etc/bind/named.conf.local
  • /etc/bind/named.conf.default-zones

ゾーンの設定は「named.conf.local」に記述します。

root@dns0:/# vi /etc/bind/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";

zone "yellow.in.net" {
      check-names ignore;
      type master;
      file "/var/lib/bind/db.yellow.in.net";

      allow-update {
         192.168.11.0/24;
      };

      allow-transfer {
         none;
      };
};

「//」から始まる行はコメントです。

「zone」から始まって、ゾーン名に続く「{」と「}」で囲まれた部分がこのゾーン名についての設定です。

check-names ignore;既定ではホスト名にアンダーバー「_」を使えませんが、
プライベートネットワークなのでアンダーバーもOKにしています。
type master;マスターサーバーであることを宣言します。
type slave;ならマスターのコピーサーバーになります。
file “/var/lib/bind/db.yellow.in.net”;ゾーンファイルを指定します。
「/etc/bind/db.yellow.in.net」のリンクを指定しています。
※下記で解説。
allow-update {
192.168.11.0/24;
};
アップデートを受け付けるネットワークの範囲やipアドレスを
設定します。
allow-transfer {
none;
};
マスターだけなので、セカンダリー サーバーにゾーン転送はしません。

ゾーンファイルのリンクを「/var/lib/bind/」に作ります。

ln -s /etc/bind/db.yellow.in.net /var/lib/bind/db.yellow.in.net

ゾーンファイルのリンクを「/var/lib/bind/」に作る理由は次の通りです。

  • BINDはユーザー「bind」で起動される。
  • BINDはアップデート情報をゾーンファイルと同じ場所に保存する。
  • BINDは「/etc/bind」ディレクトリーへの書き込み権限を持っていない。
  • BINDが書き込み権限を持っているのは「/var/lib/bind」ディレクトリー。

なので「named.conf.local」に「ゾーンファイル本体ではなくリンクの場所」を設定します。

アップデート情報はジャーナル「/var/lib/bind/db.yellow.in.net.jnl」に保存されます。

「ジャーナル」とは「変更履歴」です。

ジャーナルはマスターからスレーブ(セカンダリー)にゾーンを転送する際に整合性をとる機能もあります。

設定は完了です。

BINDを再起動します。

root@dns0:/# /etc/init.d/bind9 restart

あるいは、コンテナを再起動します。

fumi@y3:~$ docker restart dns0

Linuxからアップデートする

BINDのアップデートは「nsupdate」コマンドで行います。

以下の設定をしたので、このネットワークからはどこからでもアップデートを受け付けます。

allow-update {
         192.168.11.0/24;
};

nsupdateを使う

Debianでは「dnsutils」パッケージにコマンドが入っているので、インストールします。

root@dns0:/# apt -y install dnsutils

アップデートコマンド

コマンドの一連の流れです。

root@dns0:/# nsupdate -d
> server 127.0.0.1
> zone yellow.in.net
> update add pbx1 86400 IN A 192.168.11.12
> send
Sending update to 127.0.0.1#53
Outgoing update query:
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id:  30272
;; flags:; ZONE: 1, PREREQ: 0, UPDATE: 1, ADDITIONAL: 0
;; ZONE SECTION:
;yellow.in.net.			IN	SOA

;; UPDATE SECTION:
pbx1.			86400	IN	A	192.168.11.12


Reply from update query:
;; ->>HEADER<<- opcode: UPDATE, status: REFUSED, id:  30272
;; flags: qr; ZONE: 1, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0
;; ZONE SECTION:
;yellow.in.net.			IN	SOA

> quit
root@dns0:/# 

「-d」オプションを付けるとデバッグ情報を表示してくれます。

普通は「-d」オプションを付けておきます。

root@dns0:/# nsupdate -d

レコードを追加する

アップデートを送るサーバーを指定します。

> server 127.0.0.1

注意すべき点は、サーバーを指定しない場合、既定で「resolv.conf」に設定されているdnsサーバーをアップデートしようとします。

ところが、DockerではホストにDNSが立っており、コンテナ同士がお互いを解決できるようになっています。

Dockerコンテナは作成時に指定しなければ、DockerホストのDNSを参照します。

コンテナの「/etc/resolv.conf」は以下のようになっています。

nameserver 127.0.0.11
options ndots:0

「127.0.0.11」はDockerホストのDNSです。

従って、Dockerコンテナからnsupdateを使う場合は、「サーバーの指定は必須」です。

続いて「zone」を指定します。

> zone yellow.in.net

pbx1.yellow.in.netの「Aレコード」「192.168.11.12」を登録します。

> update add pbx1 86400 IN A 192.168.11.12

「zoneを指定していない場合」はzone情報も併せてアップデートすればOKです。

> update add pbx1.yellow.in.net 86400 IN A 192.168.11.12

最後にアップデートクエリをサーバーに送信します。

> send

送信結果が表示されます。

複数のアップデートがある場合には、「send」の前に、それらを入力することができます。

「send」の代わりに「空行にエンターキー」を押しても、アップデートが実行されます。

> ⏎

終了は「quit」です。

レコードの登録は「update add」で行います。

「update add」「ホスト名」「キャッシュ時間」「IN」「レコード」「ipアドレス」

1個以上のスペースかタブで区切って、この順番で並べます。

レコードを削除する

root@dns0:/# nsupdate -d
> server 127.0.0.1
> update delete pbx1.yellow.in.net
> ⏎
Reply from SOA query:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id:  28428
;; flags: qr aa rd ra; QUESTION: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0
;; QUESTION SECTION:
;pbx1.yellow.in.net.		IN	SOA

;; AUTHORITY SECTION:
yellow.in.net.		86400	IN	SOA	dns0.yellow.in.net. fumi.yellow.in.net. 11 604800 86400 2419200 86400

Found zone name: yellow.in.net
The master is: dns0.yellow.in.net
Sending update to 192.168.11.2#53
Outgoing update query:
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id:  56730
;; flags:; ZONE: 1, PREREQ: 0, UPDATE: 1, ADDITIONAL: 0
;; UPDATE SECTION:
pbx1.yellow.in.net.	0	ANY	ANY	


Reply from update query:
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id:  56730
;; flags: qr; ZONE: 1, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0
;; ZONE SECTION:
;yellow.in.net.			IN	SOA

> quit

登録の削除は「update delete」です。

そのホストについてのすべてのレコードを削除する場合は、ホスト名だけでOKです。

「update delete」 「ホスト名」

レコードを更新する

root@dns0:/# nsupdate -d
> server 127.0.0.1
> update delete pbx1.yellow.in.net
> update add pbx1.yellow.in.net 86400 IN A 192.168.11.13
> ⏎
Reply from SOA query:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id:   8624
;; flags: qr aa rd ra; QUESTION: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0
;; QUESTION SECTION:
;pbx1.yellow.in.net.		IN	SOA

;; AUTHORITY SECTION:
yellow.in.net.		86400	IN	SOA	dns0.yellow.in.net. fumi.yellow.in.net. 13 604800 86400 2419200 86400

Found zone name: yellow.in.net
The master is: dns0.yellow.in.net
Sending update to 192.168.11.2#53
Outgoing update query:
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id:  54513
;; flags:; ZONE: 1, PREREQ: 0, UPDATE: 2, ADDITIONAL: 0
;; UPDATE SECTION:
pbx1.yellow.in.net.	0	ANY	ANY	
pbx1.yellow.in.net.	86400	IN	A	192.168.11.13


Reply from update query:
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id:  54513
;; flags: qr; ZONE: 1, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0
;; ZONE SECTION:
;yellow.in.net.			IN	SOA

> quit
root@dns0:/# 

「update delete」して「update add」のあとに「⏎」です。

複数のアップデートを一度に行うと、「アップデート クエリ」が一度で済むので経済的です。

Windowsからアップデートする

Windows10に「Debianアプリ」をインストールして、「nsupdate」を使うこともできます。

ここでは、Windows用のBINDに含まれているnsupdate.exeを使う方法を解説します。

nsupdate.exeをインストールする

Microsoft Visual C++ をインストール

まず、nsupdate.exeを実行するために必要な「Microsoft Visual C++」をインストールします。

最新のサポートされる Visual C++ のダウンロードからダウンロードできます。

パソコンの環境に合わせてアーキテクチャを選んでダウンロードします。

「ライセンス条項および使用条件に同意する(A)」にチェックを入れて、インストールを開始します。

BINDを展開する

ISCのサイトからBINDをダウンロードします。

BIND 9
Versatile, classic, complete name server software

BINDをインストールするのではなく、パッケージに含まれている「nsupdate.exe」を使うことが目的なので、開発版でも安定板でもOKです。

ダウンロードしたファイルを「右クリック」して「すべて展開(T)…」をクリックします。

展開したフォルダの中に「nsupdate.exe」があります。

アップデートコマンド

nsupdate.exeはコマンドプロンプトで実行します。

パスが通っていないので、nsupdate.exeがあるフォルダに移動します。

C:\Users\yellow>cd Downloads\BIND9.16.20.x64

nsupdate.exeを「-d」オプションを付けて実行します。

C:\Users\yellow\Downloads\BIND9.16.20.x64>nsupdate.exe -d

ここでWindows Defenderのファイアウォールについての警告が出ることがあります。

プライベートネットワークでのアクセスを許可してください。

pbx1.yellow.in.net のAレコードを登録してみます。

C:\Users\yellow\Downloads\BIND9.16.20.x64>nsupdate.exe -d
> server 192.168.11.2
> zone yellow.in.net
> update add pbx1.yellow.in.net 86400 IN A 192.168.11.12
> ⏎
Sending update to 192.168.11.2#53
Outgoing update query:
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id:  23152
;; flags:; ZONE: 1, PREREQ: 0, UPDATE: 1, ADDITIONAL: 0
;; ZONE SECTION:
;yellow.in.net.                 IN      SOA

;; UPDATE SECTION:
pbx1.yellow.in.net.     86400   IN      A       192.168.11.12


Reply from update query:
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id:  23152
;; flags: qr; ZONE: 1, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0
;; ZONE SECTION:
;yellow.in.net.                 IN      SOA

> quit

C:\Users\yellow\Downloads\BIND9.16.20.x64>

DNSを便利に使う

プライベートネットワーク用のDynamicDNSを設定しました。

検索にこのDNSを設定すれば、ネットワーク内のホストにipアドレスではなくホスト名でアクセスできるようになります。

ところが、ホストの検索にはゾーン名(ドメイン名)も併せて指定しなければ検索結果に至りません。

同じネットワーク内にあるのに「pbx1.yellow.in.net」と入力するのは面倒です。

「pbx1」だけ入力すればOKにしたい。

解決方法は、ネットワーク内のコンピューターをゾーンに入れてしまえばいいのです。

DHCPでドメインを設定する

DHCPでドメイン名を配布するれば、Windows、Linux、その他のOSでもコンピューターが自動的にドメインを設定します。

WifiルーターもDHCPでドメイン名を配布することができます。

無線ルーター「WCR-1166DS」の場合、「LAN」→「LAN」の「DHCPサーバー設定 [拡張設定]」で拡張設定を表示して、「ドメイン名の通知」を設定します。

ヤマハのルーターなら次のように「dhcp scope option」を設定します。

dhcp scope option 1 dns=192.168.11.2 domain=yellow.in.net

固定 ipアドレスのコンピューターにドメインを設定する

固定でipアドレスを設定している場合はDHCPを使わないので、個別に設定する必要があります。

Windowsにドメインを設定する

Windowsでは、「ネットワーク アダプターのプロパティ」を表示し「インターネット プロトコル バージョン4(TCP/IPv4)のプロパティ」 で「詳細設定(V)…」ボタンをクリックして「TCP/IP 詳細設定」を表示します。

「DNS」タブを開き、「この接続のDNSサフィックス(S):」にドメイン名を設定します。

DNSサーバーがBINDなので「この接続のアドレスをDNSに登録する(R)」は機能しませんのでチェックを外しておきます。

Linuxにドメインを設定する

UNIX系のOSはresolv.confにドメインを設定します。

domain yellow.in.net
nameserver 192.168.11.2

これで、「pbx1」を入力すれば、dnsは「pbx1.yellow.in.net」のipアドレスを回答してくれます。

まとめ

Dockerでサーバーを複数作る場合は、ホストの検索が大変です。

ホスト名をDNSで解決する方法は、汎用性が高く、リソースの節約になります。

ゾーン名(ドメイン名)をDHCPサーバーに設定しておけば、ユーザーはドメイン名を省略してホストを検索できます。

DNSサーバーがネットワーク内にあると便利です。

タイトルとURLをコピーしました