ytooyamaのブログ

サーバ構築とか、仕事で発見したこととか、趣味のこととかを書いています。

Ubuntu 17.04以降にdnsmasqをインストールする方法

家で動いている複数のサーバーを統合しようと思いました。これまでRaspberry PiでDNSサーバーとNTPサーバー、Mac mini上のVMのCentOS Linuxでそれのサブ、openSUSEでコンテナレジストリーサーバーを動かしていました。OSが統一されていないのは無計画に色々動かしたためです。

全てLinuxではありますが、ディストリビューションが異なると色々と大変です(メンテナンス方法を変える必要があるため)。CentOSがStreamへ方針変更されることになりましたし、じゃあCentOS Streamを使うかというとサーバー用途で使うのはちょっと違うらしいとのことなので、2年おきに5年サポートと決められてリリースされるUbuntu Serverを使ってみようかなと思いました。

Ubuntuは普段、仕事場で技術検証などの際に使っていますし、OpenStackだ、Kubernetesだ、Rancherだと、何をするにもUbuntuを使うことが多くなってきたので、どうせ使うなら慣れているものを使おうと思ったわけです。問題なのは、Ubuntuのサポート期限が5年(OSS利用の場合。有償契約を結ぶと10年)であること、2年おきにLTSリリースがあって5年サポートなのでLTSバージョンを2つまたぎでもちょっとだけ余裕があるのでいい反面、割と2年おきにOS自体に結構な変更があるので場合によっては再学習が必要なことが気がかりだったりします。えっ、慣れていないじゃないかって?ふふふ。

Ubuntu 20.04でdnsmasqをインストールしてみた

参考情報としては以下のサイトの手順を参考にしました。とは言っても別のOSでは使ったことがあるので、手順を見ただけです。

www.server-world.info

早速、DNSサーバーとして利用していたdnsmasqをインストールするのですが、早速ここで詰まります。インストールすることはできるのですが、dnsmasqサービスが起動しないのです。

~$ sudo apt install dnsmasq
Setting up dnsmasq (2.80-1.1ubuntu1.3) ...
Created symlink /etc/systemd/system/multi-user.target.wants/dnsmasq.service → /lib/systemd/system/dnsmasq.service.
Job for dnsmasq.service failed because the control process exited with error code.
See "systemctl status dnsmasq.service" and "journalctl -xe" for details.
invoke-rc.d: initscript dnsmasq, action "start" failed.
● dnsmasq.service - dnsmasq - A lightweight DHCP and caching DNS server
     Loaded: loaded (/lib/systemd/system/dnsmasq.service; enabled; vendor preset: enabled)
     Active: failed (Result: exit-code) since Mon 2021-03-29 06:28:56 UTC; 5ms ago
    Process: 2074 ExecStartPre=/usr/sbin/dnsmasq --test (code=exited, status=0/SUCCESS)
    Process: 2089 ExecStart=/etc/init.d/dnsmasq systemd-exec (code=exited, status=2)

Mar 29 06:28:56 dnsmasq systemd[1]: Starting dnsmasq - A lightweight DHCP and caching DNS server...
Mar 29 06:28:56 dnsmasq dnsmasq[2074]: dnsmasq: syntax check OK.
Mar 29 06:28:56 dnsmasq dnsmasq[2089]: dnsmasq: failed to create listening socket for port 53: Address already in use
Mar 29 06:28:56 dnsmasq dnsmasq[2089]: failed to create listening socket for port 53: Address already in use
Mar 29 06:28:56 dnsmasq dnsmasq[2089]: FAILED to start up
Mar 29 06:28:56 dnsmasq systemd[1]: dnsmasq.service: Control process exited, code=exited, status=2/INVALIDARGUMENT
Mar 29 06:28:56 dnsmasq systemd[1]: dnsmasq.service: Failed with result 'exit-code'.
Mar 29 06:28:56 dnsmasq systemd[1]: Failed to start dnsmasq - A lightweight DHCP and caching DNS server.
Processing triggers for libc-bin (2.31-0ubuntu9.2) ...
Processing triggers for systemd (245.4-4ubuntu3.4) ...
Processing triggers for man-db (2.9.1-1) ...
Processing triggers for dbus (1.12.16-2ubuntu2.1) ...

なぜかというと、Ubuntu Server 17.04以降でsystemdの利用が本格的になっていて、Ubuntu Server 17.04でsystemd-resolvedが、Ubuntu 17.10でsystemd-networkdが使われるようになっています。そしてUbuntu Server 17.10ではネットワークの設定のクライアントとして Netplan.ioというものがフロントエンドとして使われるようになりました。設定が行われると、ネットワーク関連はsystemd-networkd(注: Ubuntu Desktopでは20.10時点でnetworkdではなく、Network Managerが使われています)に、resolve関連はsystemd-resolvedに命令を出して設定が行われます。

dnsmasqから見るとsystemd-resolvedがDNSサーバーを提供しているように見えるので、同じサービスが一台のマシン上で動いていると判断されてサービスが起動できなかったようです。

networkdを諦めてNetwork Managerを使ってみたら別の問題が発生

以前やった方法でnetworkdからNetwork Managerに切り替えてみました。一件うまく動いたのですが、nmtuiで設定してもDNS由来の設定が反映されませんでした。おまけに再起動すると/etc/resolve.confが空ファイルになって、aptコマンドなどが通らなくなりました。何か設定が足りないようです。確かNetwork Managerの設定にdnsmasqを使う設定を書き足さないといけなかったはずですが、ちょっと忘れました。

(以下の三行だけ書く)
~$ sudo vi /etc/netplan/00-installer-config.yaml
# Let NetworkManager manage all devices on this system
network:
  version: 2
  renderer: NetworkManager

(Network Managerを入れる)
~$ sudo apt install network-manager && sudo reboot

(IPアドレスの設定)
~$ sudo nmtui

この方法を諦めて、networkd+resolvedベースで動かす方法をもう少し真面目に調べることにしました。

インストールしたdnsmasqを正常に動かすには

助言してもらった情報や自分で調べたところ、設定にコメントでDNSが複数ある場合この設定のコメントを外せと書かれていました。 次の設定のコメントを外してサービスを再起動するだけで正常に動きました。

~$ sudo vi /etc/dnsmasq.conf
...
# On systems which support it, dnsmasq binds the wildcard address,
# even when it is listening on only some interfaces. It then discards
# requests that it shouldn't reply to. This has the advantage of
# working even when interfaces come and go and change address. If you
# want dnsmasq to really bind only the interfaces it is listening on,
# uncomment this option. About the only time you may need this is when
# running another nameserver on the same machine.
bind-interfaces

サービスを起動します。

~$ sudo systemctl start dnsmasq

これでdnsmasqは正常に動くようになります。

簡易DNSサーバーとしてdnsmasqを使うには

dnsmasqを簡易DNSサーバーとして使う場合の最低限の設定は次の通りです。これだけで簡易的なDNSサーバーとして利用できます。

~$ cat /etc/dnsmasq.conf| grep -v ^# | grep -v ^$
port=53
domain-needed
bogus-priv
local=/local.example.com/
interface=enp0s5
listen-address=192.168.0.7
bind-interfaces
expand-hosts
domain=local.example.com

(上記のlocal.example.comの部分は、所有するドメインに置き換えて設定しています)

[4/11/2021 追記]

interfaceはカーネルのバージョンによっては指定するとdnsmasqの自動起動に失敗することがあるらしいので、指定しない方が良いかもしれない。 listen-addressとして、サービスの応答を行うIPアドレスを指定する方が良いと思われる。

あとは dnsmasqサービスを動かすノードの /etc/hosts にIPアドレスとホスト名を列挙していけば、ホストを名前引きできるようになります。エントリを追加したらdnsmasqサービスを再起動します。

~$ cat /etc/hosts
...
192.168.0.1     router
...

~$ sudo systemctl restart dnsmasq

同じネットワークに接続されているマシンから名前解決をためしてみます。 下記の通り、問題なく動きました。

ytooyama@mymac(16:05:43) ~
% dig @192.168.0.113 router.local.example.com

; <<>> DiG 9.10.6 <<>> @192.168.0.113 router.local.example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 9394
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;router.local.example.com.  IN  A

;; ANSWER SECTION:
router.local.example.com. 0 IN  A   192.168.0.1

;; Query time: 39 msec
;; SERVER: 192.168.0.113#53(192.168.0.113)
;; WHEN: Mon Mar 29 16:06:08 JST 2021
;; MSG SIZE  rcvd: 69

最後に

というわけでUbuntuでdnsmasqを動かせるようにはなりましたが、実際移行するかについてはちょっと考え中だったりします。実はこの程度のサービスをホストするくらいならCentOS Streamでも動きます。CentOS Linux 8の後継としてCloud Linuxが開発しているAlmaLinuxとやらも普通に使えそうです。なんなら普段よく使うFedoraでもopenSUSEでもいいですし。というわけで検討中だったりします。

このブログサイトはJavaScriptを使っていますが、読み込んでいるJavaScriptは全てはてなが提供しているものであり、筆者が設置しているものではありません。