技術

Google DomainsでDDNSして更新時にSlackに通知するスクリプト

この記事を3行で

  • Google DomainsにDDNSを設定して、IP変更通知が起きたらSlackに通知したい
  • 既存DDNSクライアントアプリを使うと処理組みこむのが難しいので、ShellScript + cron で定期処理して更新処理と通知処理を混ぜ込んだ
  • 成果物: https://gitlab.chatagiriii.com/open/google-domains-ddns/-/tree/main

Google Domainsいいですよ

chatagiriです。

お名前ドットコムのddns client scriptの記事にアクセスされる方やたら多いようなので、google domains版の記事も書いておきます。

本ブログも配下にあるchatagiriii.comのドメインは某名前ドットコムで取得しました。

ですが、某名前コムの管理UIはあまりよいとは思えず、ログインにやたら時間掛かったり、画面遷移にやたら時間掛かったり、挙句の果てにはログイン後に必ずドメイン更新ページに飛ばされたりと、ウウーンとなる部分が多いものでございました。

ドメインはレジストラ間での移管が可能ですから、chatagiriii.comもGoogle Domainsに移管して、めでたく1年ほど経過しました。

サイトは軽い、変な広告見せられる事もない、レコード編集もしやすいとあって、かなり快適に利用させていただいています。

DDNSという仕組み

Google Domainsには、自動で特定DNSレコード書き換えてくれるDDNSという仕組みが実装されています。

簡単に言えば、各種サーバに付いている外見えのIPアドレスと、DNSレコードに書いてあるIPアドレスを比較して、差分があれば自動でDNSレコードを更新する仕組みです。

調べれば沢山でるので、詳細は色々調べてみて貰えればと思います。

Google DomainsでDDNSする方法

Google DomainsにDDNS通知するには主に下記2通りの方法があります。
1. DDNSクライアントを設定する(例: DDclient, INADYN)
2. GoogleDomains提供のAPIエンドポイントにHTTPリクエストを投げる

1.のDDNSクライアントを設定する方法は非常にお手軽で、pkgをインストールしてあげて設定ファイルを置くことで簡単にDDNSreadyな設定が完了します。

一方の2.はcURLやHTTPie等のHTTPクライアントコマンドから投げてあげるのが一般的になると思います。もちろん、Python, RubyのHTTPクライアントを使っても同じ事が可能でありましょう。

DDNSの仕組み作っといてよかった例

DDNSの仕組みが役に立った例で言うと、

  • chatagiriが実家に帰省してる最中に、自宅サーバを繋いでいるルータが再起動。
  • するとプロバイダから割り当てられたIPv4 Global IPが変わって、自宅鯖にLAN外からアクセス出来なくなった。
  • DDNSでchatagiriii.comのAレコード自動更新の仕組み作っておいたので、30分後ぐらいにコネクション確保。

したことがありました。感謝、仕込んでおいた過去の自分。

DDNS発火した更新時にSlackに通知したいんです..

いくらDDNSの仕組みを整えたとは言え、IPが変わったタイミングはある程度把握しておきたいもの。

slackにIP変わったタイミングを通知してあげて、ついでサーバ機の外見えIPアドレスも一緒に投げてあげれば最悪IPアドレスでSSHできるようになるので設定したいところです。

しかし、前項, 1.のDDNSクライアントを使う方法では言うなれば自由に処理組み込んであげることが難しく、「処理後にSlackに通知する」ことを追加実装するのは今の自分には厳しいなぁというおきもち。

ので、2.のHTTPクライアントコマンドからGoogle DomainsのAPIを叩いてレコードを更新して、処理後に別途SlackのWebhook宛に通知してあげるshellscriptな仕組みを作ります。

準備: DDNSアカウント, Slack Webhook準備

今回作るスクリプトに必要なものは以下な感じです。

外部サイトにそれぞれ取得方法をまとめて頂いている先人の方がいらっしゃるので、お手数ですがそちらをご参照ください。

実装: DDNS更新 ->Slack通知

前準備と実行例、コードはこんな感じで

0.前準備、ディレクトリを持って来る

こちらのgitに置いてあります

$ git clone {URL}.git

1.ddns.confファイルを弄る。
日本語な部分を全部消して置き換えてください。

# ddns.conf
TARGET_DOMAIN="ここにドメイン名を入れてください"
SLACK_PAYLOAD_URL="ここにslack通知用WebhookURLを入れてください"
GD_USERNAME="ここにGoogleDomainDDNSのユーザ名を入れてください"
GD_PASSWORD="ここにGoogleDomainDDNSのパスワードを入れてください"

2.スクリプト実行

$ update_google_ddns.sh
// slackに通知が飛んでいること
// dig した結果が新IPを向いていること

3. 問題なければcron設定を追加(スクリプトの置き先パスは各々変更してください)

# vim /etc/cron.d/update_google_ddns

SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
*/5 * * * * root bash -c '/etc/tools/update_google_ddns.sh'
// スクリプトのパスは各々が適切に変更してください↑ 

コード

#!/bin/bash

# 変数読み込み
source $(cd $(dirname $0); pwd)/ddns.conf

IP_TMP_FILE="/var/tmp/.${TARGET_DOMAIN}_recent_ip"

function check_ipaddr(){
  touch "${IP_TMP_FILE}"
  MYIP=$(curl -s4G ip-addr.net)
  OLDIP=$(cat ${IP_TMP_FILE})
  if [[ ${MYIP} == ${OLDIP} && ${MYIP} != "" ]]; then
      return 0
    else
      return 1
  fi
}

function update_ddns() {
  # IPアドレス変更検知をslackに通知
  curl -XPOST -s --data-urlencode "payload={\"text\":\"Differed IP address found in chatagiriii.com OLD: ${OLDIP} NOW: ${MYIP} \"}" "${SLACK_PAYLOAD_URL}"

  # Google Domains APIに対してレコード更新リクエスト
  local GD_RES=$(curl -s -H "Content-Type: application/json" -H "Content-Length: 0" -H "User-Agent: chatagiriii.com" --user "${GD_USERNAME}:${GD_PASSWORD}" -XPOST "https://domains.google.com/nic/update?hostname=chatagiriii.com&myip=${MYIP}")
  # 反映待ち 
  sleep 5;

  # レコード更新リクエストの実行結果とdigった結果をslackに通知
  curl -XPOST -s  --data-urlencode "payload={\"text\":\"Google Responce: ${GD_RES}, dig result: $(dig +short @8.8.8.8 ${TARGET_DOMAIN}) \"}" "${SLACK_PAYLOAD_URL}"
 
  # IP差分確認用ファイル更新
  echo "${MYIP}" > "${IP_TMP_FILE}"
}

function main(){
 
    # check_ipaddrでipアドレス差分が判明した場合,update_ddns
    check_ipaddr || {
      update_ddns
    }
}

main

特に難しい処理はしていませんし動けば良いと思って書いている突貫スクリプトです。誰か綺麗に書き直してください

  • スクリプトを動作するサーバの外に出る、実行時現在のIPv4アドレスをpublicなサービス(ip-addr.net)で取得して保持。
  • 保持してたファイルに書いてある、過去のIPアドレスと実行時現在のIPアドレスに差分があればmain実行。
    • Google DomainsのAPIエンドポイントに毎度毎度リクエストを投げるとRateLimitに引っ掛かっていざという時に更新できない話を聞いたのでこういう感じにしています
  • 実行結果をslackに通知
  • 全処理完了後、新旧IPアドレス差分確認用ファイルを更新

ソースはこちらに置いておきます

これでルータ再起動しても怖くないぞォ

これでcronがスクリプトたたいてくれるので、Google DomainのDNSレコードと、サーバ機の今現在の外見えIPアドレスに差分があればDNSレコードを自動更新して、かつslackに通知が来るようになりました。

もともとinternal useなものだったのできたねえコードになってますが、もっと綺麗なスクリプト書ける様に精進いたしやす。。

-技術