こんにちは、Juntechです。
私は作業場にサーバを置いているのですが、
IP固定ができないため、うっかりルータを再起動するなどして、
グローバルIPがわからなくなってしまうことがよくあります。

そこで今回は、GoogleスプレッドシートとIFTTTを使って、
グローバルIPが変わった時に自動通知してもらおうと思います。

まずはスキーム

こんな感じでやります。

サーバーで定期的にIPを取得し、前回のIPと比較をします。
IPに変更があればWebhookを使ってIFTTTへPOSTし、
IFTTTからLINEへ通知します。

実装する

IFTTTの設定

まずはIFTTTの設定を済ませます。
https://ifttt.com/home

IFTTTとは、さまざまなサービスの間に入って、
データのやりとりを自動化できるサービスです。
最近だと、スマート家電が有名になったことで、
各種サービスとデバイスを連携する手段としてこのサービスを聞いたことのある人も多いかと思います。

今回はこのIFTTTで、サーバからPOSTした情報をLINEに連携します。
アカウント作成ができたら、右上メニューの「Create」を選択します。

するとこんな感じで、シンプルな設定画面が表示されます。
まずは「If This」を選択します。

検索バーに「Webhooks」と打ち込み、表示されたWebhooksのアイコンを選択します。

「Receive a web request」を選択します。

「Connect」を選択します。

Event Nameを入力し、「Create trigger」を選択します。
なおここで設定した名前は後々のAPI利用時にURLに含める必要があるため、
半角小文字でシンプルな名前を設定しておくことを推奨します。

これでIfの設定ができました。
次に「Then That」を選択します。

今度は「LINE」と入力し、いつも使っているLINEのロゴを選択します。

「Send message」を選択します。

「Connect」を選択します。

LINEのログインウィンドウが開くので、
自分のアカウント情報を入力してログインします。

LINE通知の同意取得画面が開くので、「同意して連携する」を選択します。

連携が完了すると、LINE Notifyから通知が来ます。

IFTTTの画面に戻ると、連携内容の設定画面に進んでいます。

「Recipient」では通知を受け取るグループを設定できます。
今回は1人で使うので、「1:1でLINE Notifyから通知を受け取る」を選択します。

「Message」ではLINEに送信されるメッセージを設定します。
グレー背景で「 Value1 」となっている部分には、
API実行時にリクエストボディに詰められた値がセットされます。

今回は下記で設定しておきます。

サーバー「{{Value1}}」のグローバルIPが更新されました!<br>
IPアドレス:<br>
{{Value2}}

なお、変数名「Value1」「Value2」「Value3」は固定で、
違う名前に変更することはできないようです。

設定が終わったら、「Create action」を選択します。

「Continue」を選択します。

Applet Titleをよしなに変えて、「Finish」を選択します。

これで設定が完了しました。

手動でPOSTしてみる

試しにPostmanでMessageをPOSTしてみましょう。
まずはWebhookのURLを取得します。
https://ifttt.com/maker_webhooks

上記ページにアクセスし「Documentation」を選択します。

「Your key is:」の次に表示された文字列が、自分専用のWebhookキーです。

これを使ってPOSTを行います。
PostmanでRequestを新規作成し、URLを下記にします。

https://maker.ifttt.com/trigger/:event/with/key/:key

こうすると「Params」タブに「event」と「key」のパスパラメータ設定行が表示されるため、
「event」には先ほどIFTTTでWebhooksに設定したEvent Nameを、
「key」にはWebhookキーを入力します。

Bodyタブに移動し、「raw」「JSON」を選んで、リクエストボディをセットします。

{
    "value1": "LocalServer",
    "value2": "XXX.XXX.XXX.XXX"
}

「Send」を選択するとAPIが実行され、Responseが返ってきます。

無事通りました。

少し経つと、LINEに通知が届きます。
開いてみると…

先ほどIFTTTで設定したメッセージが、POSTした値を含めて送られています。
これでAPI経由でLINE通知をすることができました。

サーバ側の実装

最後に、サーバ側の実装を行います。
なおサーバは、CentOS 7.8を使っています。
今回はShellを使って、
IPアドレスを取得→前回のIPアドレスと比較→差分があればPOST
を行います。

#!/bin/bash

FILE_GLOBAL_IP="${WORKSPACE}/GLOBAL_IP"
FILE_GLOBAL_IP_OLD="${WORKSPACE}/GLOBAL_IP_OLD"

if [ -f "${FILE_GLOBAL_IP}" ]; then
    mv "${FILE_GLOBAL_IP}" "${FILE_GLOBAL_IP_OLD}"
else
    touch "${FILE_GLOBAL_IP_OLD}"
fi

RESPONSE_STATUS=$( curl -sS ifconfig.io -o "${FILE_GLOBAL_IP}" -w "%{http_code}" )
if [ "${RESPONSE_STATUS}" != 200 ]; then
    echo "ERROR! Response Status Is ${RESPONSE_STATUS}."
    exit 1
fi

GLOBAL_IP=$( cat "${FILE_GLOBAL_IP}" )
GLOBAL_IP_OLD=$( cat "${FILE_GLOBAL_IP_OLD}" )

if [ "${GLOBAL_IP}" != "${GLOBAL_IP_OLD}" ]; then
    curl  -sS --request POST "https://maker.ifttt.com/trigger/ip/with/key/${IFTTT_WEBHOOK_KEY}" \
    --header "Content-Type: application/json" \
    --data-raw "{ \
        \"value1\": \"LocalServer\", \
        \"value2\": \"${GLOBAL_IP}\" \
        }"
else
    echo "SUCCESS : IP Addres has not chenged."
fi

最初のIF分岐で、
前回のグローバルIPがあれば退避、なければ空ファイル作成
という処理を行っています。

その後グローバルIPを取得してファイルに書き込み、
同時にHTTPステータスコードを取得して変数に詰めています。
グローバルIPの取得は、curl ifconfig.io で出来ます。
IF分岐でHTTPステータスコードを確認し、200以外であれば異常終了します。

最後に、今回グローバルIPを書き出したファイルと、
最初に退避した前回のグローバルIPファイルをそれぞれcatし、
中身を比較します。

一致しなければ、IFTTTのWebHooksに対し、
今回取得したグローバルIPをPOSTします。
Webhookキーは環境変数にセットしています。

私の場合、このサーバにJenkinsを立てているので、
Jenkinsからこのスクリプトを定期実行することにしました。
Jenkinsがない場合には、crontabでスケジュール実行するのがおすすめです。


今回はここまで。

同じスキームを使うことで、これ以外にも、
サーバで検知したものを通知したい系が簡単に実現できます。
ぜひ活用してみてください。