09/30/2017, 1:35 PM GMT+9

MyDNSのレコード更新でDiCEが動かなかったのでcronで【自宅サーバー】

DiCEがうまく動かなかった

外出先から自宅サーバーでホストしているwebサイトにアクセスしたところ、MyDNSのエラーページが表示された。これは、DDNSの更新が一定期間行われていないことを示す。DDNSはDiCEで更新するようにしていたはずだ。systemctl status diceで状態を見ると、active (exited)だった。

当時の環境

次のようなserviceファイルを作成し、systemdで自動起動する設定にしていた。

 [Unit]
 Description=The DiCE Server
 After=network.target remote-fs.target nss-lookup.target
 [Service]
 Type=notify
 ExecStart=/usr/local/bin/DiCE/diced -d
 ExecReload=/usr/local/bin/DiCE/diced $OPTIONS
 ExecStop=/usr/local/bin/DiCE/diced $OPTIONS
 RemainAfterExit=yes
 PrivateTmp=true

 [Install]
 WantedBy=multi-user.target

systemctl start diceした直後、statusでログを見たところ、

 [[email protected] ~]$ systemctl status dice
 9月 28 19:32:09 server1 systemd[1]: Starting The DiCE Server...
 9月 28 19:32:09 server1 diced[9229]: =-=-=- DiCE DynamicDNS Client -=-=-=
 9月 28 19:32:09 server1 diced[9229]: Version 0.19 for Japanese
 9月 28 19:32:09 server1 diced[9229]: Copyright(c) 2001 sarad
 9月 28 19:32:09 server1 diced[9229]: DiCE Daemon Started !!
 9月 28 19:32:09 server1 systemd[1]: Started The DiCE Server.

特に問題はなさそう。

しかし、systemctl stopすると、なぜかしばらく制御が戻ってこない。かなり長い時間待機していると、ようやく再びコマンド入力を受け入れる状態になった。そこで、statusを確認すると、

 [[email protected] ~]$ systemctl stop dice
 9月 28 19:43:54 server1 diced[10371]: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
 9月 28 19:43:54 server1 systemd[1]: dice.service stopping timed out. Terminating.
 9月 28 19:43:54 server1 diced[10371]: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
 9月 28 19:43:54 server1 systemd[1]: Stopped The DiCE Server.
 9月 28 19:43:54 server1 systemd[1]: Unit dice.service entered failed state.
 9月 28 19:43:54 server1 systemd[1]: dice.service failed.

謎の「:」が大量に並んだログ。詳細は分からないが、とにかく正常に動いていないということだけは分かり、一筋縄ではいかなそうだったので、DiCE を使うのは諦めてcronでDDNS更新通知を行うことにした。

cron による DDNS 更新

やりたいこと

cron による DDNS 更新で何をしたいのか明確にしておく。

  • 自分のグローバル IP アドレスを取得する
  • DDNS に更新リクエストを送る
  • 上記の処理を定期的に実行する

方法

MyDNSにIPアドレスを通知するには、複数の方法がある: メール, FTP, HTTP。今回は、最も簡単そうなHTTPによる方法を採用した。HTTPによる方法には、HTTP-BASICと HTTP-DIRECTがある。今回はHTTP-BASIC による方法を採用する。

HTTP-BASIC による方法では、http://masterID:[email protected]/login.html にアクセスすることで、アクセス元のIPアドレスが通知される。

更新コマンド

実行するコマンドは次のとおりである。

wget -q -O /dev/null http://masterID:[email protected]/login.html

このコマンドが正常に動くことを確認したら、これを定期実行するようにcronに入れれば良い。

cron による自動更新

理想的な実行間隔

DiCEは定期通知の他にIPアドレスの変更を検知して通知してくれるが、cronを使って更新する場合は定期通知しかできない。そのため、できるだけ正しいIPアドレスを保持するために更新間隔は短いほうが良い。しかし、あまりにも短い更新間隔はMyDNSに負担をかけてしまうかもしれない。そこで、適切な更新間隔を設定する必要がある。

MyDNS のチュートリアルのようなページでは5分毎に通知している。これは自分が考えていたよりも短かった。IPアドレスが変わったとき、最大5分程度なら十分だろう。よって、今回は、5 分毎に実行するように設定した。

実行間隔を管理する仕組み

/etcにはcron関係のファイルを置くディレクトリが幾つかある。ディレクトリによって実行間隔が異なる。

[[email protected] etc]$ ls | grep cron
anacrontab
cron.d
cron.daily
cron.deny
cron.hourly
cron.monthly
cron.weekly
crontab

現状での最短はhourlyであるから、5分毎に実行するスクリプトのためには自前でディレクトリを作成し、登録しなければならない。

実は、dailyやmonthlyなどは0:00などに実行されるのではなく、anacrontabというものによって管理されているらしく、そのファイルの中身を見て見る限り、ある程度の遅延は許容されているらしい。確かに、0:00はcron以外にも色々なプログラムが動きそうなので理にかなっている。

しかし、hourlyはそうではなく、毎時1分に実行されるように固定されている。これは、見たところ、/etc/cron.d/0hourly というファイルで定義されているようだ。

# Run the hourly jobs
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
01 * * * * root run-parts /etc/cron.hourly

一番最後の行がメイン。これを見る限り、毎時 0 分ではなく毎時 1 分に実行されるらしい。

設定

では、先程のファイルをコピーし、最後の行を書き換えてやれば5分毎の実行ができそう。

[[email protected] etc]$ sudo mkdir cron.everyfivemin
[[email protected] etc]$ cd cron.d
[[email protected] cron.d]$ sudo cp 0hourly every5minutes
[[email protected] cron.d]$ ls
0hourly clamav-update every5minutes raid-check sysstat
[[email protected] cron.d]$ sudo vim every5minutes
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
*/5 * * * * root run-parts /etc/cron.everyfivemin

そして /etc/cron.everyfiveminmydnsファイルを作成。中身に、前述したDDNS更新スクリプトを書く。
ちなみに、当たり前だけどpermissionにxがないと実行できない。だから644とかは不可。何を当たり前のことをと思うかもしれないが、自分が引っかかってしまったので…

これで完了。


Cosnomi
Cosnomi

コンピュータ(Web, 機械学習など)が好きな医学部生

Twitter / GitHub