avahiで自分のIPアドレスに複数のホスト名をエイリアスする

家のRaspberry Piにいくつかサーバーを立てていて、ポート番号を分けてアクセスしていたのだけど、番号だと分かりづらい。ホスト名でアクセスできるようにしたい。

DNSサーバーは立てずに、ホスト名は mDNS (avahi)で解決できるようにする。Raspbian Busterはデフォルトでavahiが動いているので、その設定を変える。

1つのIPアドレスに複数の名前を登録する

avahi は、/etc/avahi/hosts にホスト名-IPの組み合わせを書くと広報してくれる。ただし、同じIPアドレスのホストを複数登録できない。ホスト名.local はデフォルトで広報されるようになっているので、自分のホスト名にエイリアスをつけられない。追加するホスト名ごとにIPアドレスも追加してやればよいが、そういう事ではないような気がする。

/etc/avahi/hosts ではこのような制限があるが、avahi-utilsに入っている avahi-publishというコマンドで、-R --no-reverse というオプションをつければ登録できる。こんな感じ:

avahi-publish -a -R aaa.hostname.local 192.168.1.9 &
avahi-publish -a -R bbb.hostname.local 192.168.1.9 &

このコマンド、起動しっぱなしにしておかなくてはいけないらしく、バックグラウンドで動かしている点に注意。あと、上のコマンドだとログオフすると終了してしまうので注意。

自動化

ホストを起動したときに自動的に設定されるようにしたい。検索するとよく出てくる、systemdのサービスとして実行する方法を取る。{ホスト名}.localのサブドメインを設定するようにした。現在のIPアドレスは、eth0の"inet"から取ってくる。

$ cat /etc/systemd/system/avahi-subdomain@.service
[Unit]
Description=Publish %I.%H.local as alias for %H.local via mdns
Requires=avahi-daemon.service
After=avahi-daemon.service

[Service]
Type=simple
ExecStart=/bin/bash -c "/usr/bin/avahi-publish -a -R %I.%H.local $(ip a show dev eth0 | awk '$1==\"inet\"{print $2}' | cut -d/ -f1)"
Restart=on-failure
RestartSec=3

[Install]
WantedBy=multi-user.target

avahi-subdomain@{サブドメイン}.service でサービス登録&起動

 $ systemctl enable --now avahi-subdomain@gr.service
 $ systemctl status avahi-subdomain@gr.service
● avahi-subdomain@gr.service - Publish gr.hostname.local as alias for hostname.local via mdns
   Loaded: loaded (/etc/systemd/system/avahi-subdomain@.service; enabled; vendor preset: enabled)
   Active: active (running) since Sun 2020-10-11 17:00:42 EDT; 1min 6s ago
 Main PID: 23264 (avahi-publish)
    Tasks: 1 (limit: 2065)
   CGroup: /system.slice/system-avahi\x2dsubdomain.slice/avahi-subdomain@gr.service
           └─23264 /usr/bin/avahi-publish -a -R gr.hostname.local 192.168.1.9

IPv6対応

サーバー(Raspberry Pi)もクライアント(Mac)も、IPv6を有効にしている。このとき、SafariIPv6で名前解決して失敗したらIPv4にフォールバックしないのを忘れていた。IPv6も名前登録するようにする。

少しコマンドが長くなるので、シェルスクリプトを実行するように変更した。

 $ cat /usr/local/bin/avahi-add-subdomain.sh
#!/bin/bash
set -e
SUBDOMAIN=$1
HOSTNAME=$(uname -n)
ADDRS=$(ip a show dev eth0 | awk '$1~/inet/{print $2}' | cut -d/ -f1)

for ADDR in $ADDRS; do
    echo "Add $SUBDOMAIN.$HOSTNAME.local $ADDR"
    /usr/bin/avahi-publish -a -R $SUBDOMAIN.$HOSTNAME.local $ADDR&
done
wait

最後にwaitを入れないとバックグラウンドジョブが実行されない。スクリプト単体で実行すると問題ないのだけど。なぜだろう。。

 $ cat /etc/systemd/system/avahi-subdomain@.service
[Unit]
Description=Publish %I.%H.local as alias for %H.local via mdns
Requires=avahi-daemon.service
After=avahi-daemon.service

[Service]
Type=simple
ExecStart=/usr/local/bin/avahi-add-subdomain.sh %I
Restart=on-failure
RestartSec=3

[Install]
WantedBy=multi-user.target

References