私的サーバー構築日誌：dhcpサーバー冗長化

# 能書き

[私的サーバー構築日誌：仕切り直し](https://qiita.com/katz_engineer/items/1f21de2bd9072c260ae6)からの自宅サーバー構築の続きです。

今回はDHCPサーバーの冗長化を図ります。既に何度か実施して手順は確立していますが、細かい手順の修正もありますので、改めて記事を起こします。

以下、何度か書いている能書きの再掲です。

一般的な家庭においては、家庭内LANに接続されるマシンのIPアドレスは無線LANルータなどの内蔵DHCPサーバーが割り振る事になります。これを無効化する設定も可能ですけど、まあ普通はしませんよね。わざわざ手間を掛けて、今時どうでもいいような枯れた技術であるDHCPサーバーをインストール・設定する人はあんまり居ないでしょう。

今回はその点でちょっとしたイタズラです。

ちょっとやそっとでは機能を停止しないような、可用性の高いパソコン環境を家庭内に構築する事は私の長年の夢でした。というか今まで何度も痛い目に遭って不本意ながら涙目の思い出を積み上げてきてしまった私としては、堅牢な環境の構築は非常に重要な目標なのです！（力説）

という訳で、ちょっとだけ言葉のおさらいを。

私の目指してる、二重化による高可用性サーバーはHAクラスタと言うらしいですな。Linuxを利用したクラスタはLinuxクラスタと呼ばれます。今回はその第一歩としてIPアドレスを高可用化する事になります。

そんな訳でDHCPサーバーの多重化を試みます。同時にIPアドレス設定に関する覚え書きを残せるようにします。家庭向け無線LANルータの内蔵DHCPサーバーでは、コメントを残す機能なんてありませんので。AirMacでは残せたんですがね。

## 我が家のIPアドレス体系

DHCPサーバーを立てる前に、家庭内のIPアドレス体系を見直します。[以前も同じ事をやりました](https://qiita.com/katz_engineer/items/dfc77db6d48f0e2d3cd8)ので、その再掲になります。クラスBにして、第3オクテットで分類して使い分ける方針です。

DHCPプロトコルについて。プロトコルの仕様は、LAN 内に複数のDHCPサーバーが在っても問題無く動くようになっているそうです。問題はDHCPサーバーのIPアドレス管理が同期されない事で、IPアドレスが重複して発行されてしまう事態になりかねない点にあります。だからDHCPサーバー毎にIPアドレス範囲を分離する事で、多重発行を防ぐようにすれば良い、との事。

我が家のネットワークアドレス: **172.16.0.0/16**

<dl>
<dt>172.16.0.*<dt>
<dd>エイリアスIPアドレスとして、サービス毎に割り当てる固定IPアドレス（仮想IPアドレス）</dd>
<dt>172.16.1.*</dt>
<dd>ステイショナリIPアドレスとして、NIC毎に割り当てる固定IPアドレス及びMACアドレス毎にDHCPサーバが固定的に割り当てるIPアドレス</dd>
<dt>172.16.2.*</dt>
<dd>無線LANルータ内蔵のDHCPサーバーによる動的割り当てのIPアドレス</dd>
<dt>172.16.3.*</dt>
<dd>プライマリサーバーのDHCPサーバーによる動的割り当てのIPアドレス</dd>
<dt>172.16.4.*</dt>
<dd>セカンダリサーバーのDHCPサーバーによる動的割り当てのIPアドレス</dd>
</dl>

## 目標

プライマリーサーバーを構築中ですので、ここにDHCPサーバーをインストールして、`172.16.3.*`を払い出すようにします。その際に[前回構築したDNSサーバー](https://qiita.com/katz_engineer/items/f2198e5cb7b222d4180e)を指定するようにします。

## 参考文献

枯れていて、しかも簡単な技術ですが、それでも色々トラブルがありまして、参考文献が多いです。

- [自宅サーバー構築譚：dhcpサーバ冗長化・Ubuntu 22.04 - Qiita](https://qiita.com/katz_engineer/items/dfc77db6d48f0e2d3cd8)
- [俺様サーバー構築記 - dhcp サーバ冗長化@デスクトップパソコン - Qiita](https://qiita.com/katz_engineer/items/04396d58add14cb63573)
- [自宅サーバー構築譚：dhcpサーバ冗長化 - Qiita](https://qiita.com/katz_engineer/items/a5cc92d7ca523ee3be14)
- [focal (5) dhcpd.conf.5.gz - Ubuntu manuals](http://manpages.ubuntu.com/manpages/focal/ja/man5/dhcpd.conf.5.html)
- [focal (8) dhcpd.8.gz - Ubuntu manuals](http://manpages.ubuntu.com/manpages/focal/ja/man8/dhcpd.8.html)
- [DHCPサーバ及びホスト名のみでのアクセス - Carpe Diem](https://christina04.blog.fc2.com/blog-entry-117.html)
- [dhcpd - ArchWiki](https://wiki.archlinux.jp/index.php/Dhcpd)
- [4.5. TFTP ネットブート用ファイルの準備 - 第4章 システムインストールメディアの入手 - Debian GNU/Linux インストールガイド](https://www.debian.org/releases/jessie/i386/ch04s05.html.ja)
- [(今更)Linux で HW(MAC)アドレスを取得する方法](https://qiita.com/p_cub/items/b0b4351c52c876aaa095)
- [DHCPサーバの設定 on Ubuntu 18.04](http://www.netaro.info/_blog_/2020/03/28/2020-0328_dhcp-server/)

# DHCP サーバ

## スナップショット

インストール前にスナップショットを撮ります。

```console
sudo zfs snapshot tank/root/ubuntu@$(date +%Y%m%d_%H%M%S)_before_isc-dhcp-server
```

## インストール

dhcpサーバーをインストール。

```console
sudo apt -y install isc-dhcp-server
```

インストールに成功したら`/etc`をSubversionで確認します。

```console
cd /etc
sudo svn st
```

結果は下記のようになりました。

```console
$ sudo svn st
?       apparmor.d/dhcpd.d
?       apparmor.d/local/usr.sbin.dhcpd
?       apparmor.d/usr.sbin.dhcpd
?       default/isc-dhcp-server
?       dhcp/ddns-keys
?       dhcp/dhcpd.conf
?       dhcp/dhcpd6.conf
M       group
M       gshadow
?       init.d/isc-dhcp-server
M       ld.so.cache
?       logcheck/ignore.d.server/isc-dhcp-server
M       passwd
?       rc0.d/K01isc-dhcp-server
?       rc1.d/K01isc-dhcp-server
?       rc2.d/S01isc-dhcp-server
?       rc3.d/S01isc-dhcp-server
?       rc4.d/S01isc-dhcp-server
?       rc5.d/S01isc-dhcp-server
?       rc6.d/K01isc-dhcp-server
M       shadow
?       systemd/system/multi-user.target.wants/isc-dhcp-server.service
?       systemd/system/multi-user.target.wants/isc-dhcp-server6.service
M       unbound/unbound.conf.d/machines.list
```

`ld.so.cache`は共有ライブラリの名前と実体に関するキャッシュだそうです。

AppArmorはウィルス対策ソフトの一種の模様

アカウントが増えている様子(group,gshadow,passwd,shadow)なので、ちょっと中身を確認。

```console
$ sudo svn di --diff-cmd diff -x -U0 group gshadow passwd shadow
Index: group
===================================================================
--- group       (revision 4)
+++ group       (working copy)
@@ -58,0 +59 @@
+dhcpd:x:119:
Index: gshadow
===================================================================
--- gshadow     (revision 4)
+++ gshadow     (working copy)
@@ -58,0 +59 @@
+dhcpd:!::
Index: passwd
===================================================================
--- passwd      (revision 4)
+++ passwd      (working copy)
@@ -30,0 +31 @@
+dhcpd:x:111:119::/var/run:/usr/sbin/nologin
Index: shadow
===================================================================
--- shadow      (revision 4)
+++ shadow      (working copy)
@@ -30,0 +31 @@
+dhcpd:*:19586:0:99999:7:::
```

`dhcpd`というユーザーとグループが追加されたようです。

後はinit.dとsystemdの関連ファイルが幾つかですね。

それ以外は特別な変更は無さそうですので、このまま`/etc`を`svn commit`します。

```console
sudo svn st | grep "^?" | cut -b9- | sudo xargs -I{} find {} -type f -or -type d -or -type l | sudo xargs -rt svn add
```

```console
sudo svn ci -m"installed isc-dhcp-server"
```

## 設定

いよいよDHCPサーバーを設定します。

まずはサーバーのネットワーク関係を確認します。

```console
ip a
```

こんな結果になります。

```console
$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: enp86s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 48:21:0b:58:8d:a2 brd ff:ff:ff:ff:ff:ff
    inet 172.16.1.2/16 brd 172.16.255.255 scope global enp86s0
       valid_lft forever preferred_lft forever
    inet6 fe80::4a21:bff:fe58:8da2/64 scope link
       valid_lft forever preferred_lft forever
```

これを見て、IPアドレスとNIC名を取得します。

```console
SVR_IPADDR=172.16.1.2
NIC_NAME=enp86s0
```

そして家庭内ルーターのIPアドレス。我が家はこうです。

```console
RTR_IPADDR=172.16.2.1
```

これを踏まえて`dhcpd.conf`を設定します。

```console
cat | sudo tee /etc/dhcp/dhcpd.conf >/dev/null <<___
option domain-name "home";
option domain-name-servers $SVR_IPADDR;

default-lease-time 86400;
max-lease-time 86400;

ddns-update-style none;

authoritative;

subnet 172.16.0.0 netmask 255.255.0.0 {
  range 172.16.3.2 172.16.3.254;
  option subnet-mask 255.255.0.0;
  option broadcast-address 172.16.255.255;
  option routers $RTR_IPADDR;
}

# primary server
host $(cat /etc/hostname) {
  hardware ethernet $(cat $(find /sys/devices -name $NIC_NAME)/address);
  fixed-address $SVR_IPADDR;
}
___
```

補足説明。

- `domain-name`はhomeにしましたが、きちんとドメインを購入した方はそちらを設定した方が良いでしょう。因みにlocalは危険と言われています。[homeかcorpの方が宜しい](https://www.nic.ad.jp/ja/newsletter/No57/0800.html)かと。
- `domain-name-servers`は[前回構築したUnbound](https://qiita.com/katz_engineer/items/f2198e5cb7b222d4180e)を想定しています。
- `default-lease-time`と`max-lease-time`は24時間です。ここはお好みで。実験する場合には短い方が良いかも知れません、1分とか。
- `ddns-update-style`について。知らなかったんですが、DynamicDNS的な事が出来るらしいですな。今回はその機能は使いません。
- `authoritative`については難しい事は言いません。オマジナイと思ってとにかく書く！
- `subnet`云々の箇所は、まぁ書いてある通りです。IPアドレスに関する基礎知識があれば何となく理解できるでしょう。
- `# primary server`以下の箇所はこのマシン自身の設定です。実際に役立つ設定ではなく単なるメモ書きになる筈です。`host`のホスト名は何でも良いらしいですが、実際のマシン名（`/etc/hostname`と同じ内容）を書いておいた方がメモの役に立つでしょう。

ログは設定していません。もしも何かが起きたら、上述の[参考文献](http://www.netaro.info/_blog_/2020/03/28/2020-0328_dhcp-server/)に従って設定しましょう。

## Ubuntu20.04のバグ

[Ubuntu20.04LTS にあったバグ](https://qiita.com/katz_engineer/items/a5cc92d7ca523ee3be14#ubuntu-%E3%81%AE%E3%83%90%E3%82%B0)は、Ubuntu22.04LTS ではどうやら対応されたようです。[以前のバグ対応の結果](https://qiita.com/katz_engineer/items/a5cc92d7ca523ee3be14#ubuntu-%E3%81%AE%E3%83%90%E3%82%B0)が既にそのまま存在しています。
と言う訳でバグ対応は考えなくて良さそうです。

## 起動

起動します。

```console
sudo systemctl start isc-dhcp-server
```

恐ろしい事に、エラーが発生して起動に失敗しても画面には表示されません。必ず確認しましょう。

```console
systemctl status isc-dhcp-server
```

## 確認

イケたようなので、実際に利く所を見てみましょう。

0. まずは有線LANで繋がってるマシンを用意します。
0. 今まで動いていた家庭内のDHCPサーバー（大抵は無線LANルータに内蔵の機能でしょう）だけが動いてる状態で与えられるIPアドレスを確認。
0. 上記で設定したサーバーマシンのDHCPサーバーだけが動いている状態で与えられるIPアドレスを確認。

DHCPサーバーを自分で立てようなんて酔狂な事をする同志なら、具体的な確認手順は言われずともおわかりと思いますので省略。

## 自動起動

全部上手くいったら、マシン再起動で自動起動するようにします。

```console
sudo systemctl enable isc-dhcp-server
```

良く分かりませんが、下記コマンドを実行してますというメッセージが（英語で）出ました。ちょっとした報告で、そのまま無視して構わないようです。

```console
/lib/systemd/systemd-sysv-install enable isc-dhcp-server
```

なお、[参考文献](http://www.netaro.info/_blog_/2020/03/28/2020-0328_dhcp-server/)で触れられている、マシン再起動時にDHCPサーバーが自動起動しない件ですが。
マシンが起動した直後は動いていませんが、どうも暫く待つと勝手に動き出すようです。原因は不明。少し待ったら動いたという現象がありました。ただそれだけです。

# `/etc`バージョン管理

成功を確認したら`/etc`をSubversion登録します。

```console
cd /etc
sudo svn st | grep "^?" | cut -b9- | sudo xargs -I{} find {} -type f -or -type d -or -type l | sudo xargs -rt svn add
```

```console
sudo svn ci -m"setting DHCP server"
```

# 仕舞い

これで、無線LANルーターが潰れたとしても、有線でつながっているLANの範囲はネットワークがきちんと機能する状態になりました！家庭内環境の高可用性への第一歩です。