ngrokのURLが変わったときに自動的にLINEのwebhookを更新する

# 概要

再起動のたびに変わる [ngrok](https://ngrok.com/) の URL を、自動的に [LINE Developers](https://developers.line.biz/console/) の Webhook に登録する方法です

# ngrokの弱点
ラズパイでLINE BOTを作るときに、
ラズパイ上のサービスを公開するのに非常に便利なサービスが [ngrok](https://ngrok.com/) です
無料で利用できますし、アカウント登録をすると時間制限もなくなります

こんな便利な [ngrok](https://ngrok.com/) ですが、ひとつ弱点がありまして、
再起動のたびに公開URLのアドレスが変わってしまうのです
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102797/9d15652b-37f0-21e9-5b85-edebe5fb25f1.png)
`bd2b-133-106-36-148` の部分が毎回変わります
これを毎回 [LINE Developers](https://developers.line.biz/console/) の Webhook に設定するのですが、面倒ですよね...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102797/f7224168-0573-14e9-9400-5525e22f611e.png)
***これを自動化します***

# 自動化の方法

## 目次
1. LINE の [Messaging API](https://developers.line.biz/ja/docs/messaging-api/) を利用してWebhook URLを登録する
1. 起動中の [ngrok](https://ngrok.com/) のURLを取得する
1. スクリプトで自動化する

## 1. LINE の [Messaging API](https://developers.line.biz/ja/docs/messaging-api/) を利用してWebhook URLを登録する

LINE Developersの公式ドキュメントです
https://developers.line.biz/ja/reference/messaging-api/#set-webhook-endpoint-url


`curl` を使って以下のようすればwebhookを設定できます
`CHANNEL_ACCESS_TOKEN`はLINE BOTを作るときに発行するものと同じものです
```shell
curl -X PUT \
-H 'Authorization: Bearer {CHANNEL_ACCESS_TOKEN}' \
-H 'Content-Type:application/json' \
-d '{"endpoint":"https://example.com/hoge"}' \
https://api.line.me/v2/bot/channel/webhook/endpoint
```

やってみます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102797/a845c63d-8b17-99b2-be9b-2ac400f6371a.png)
返事が `{}` だけ。シンプル...
[LINE Developers](https://developers.line.biz/console/)でwebhookが設定されていることを確認します。
うまくいっていますね
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102797/46c06015-ab5c-77fd-0f2c-8ffa696e60a1.png)

## 2. 起動中の [ngrok](https://ngrok.com/) のURLを取得する

[ngrok](https://ngrok.com/)を起動すると`Web Interface   http://127.0.0.1:4040`と表示されます
これが、実行中の [ngrok](https://ngrok.com/) のステータスを確認できるインターフェースになります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102797/9d15652b-37f0-21e9-5b85-edebe5fb25f1.png)
URLを知るには `http://127.0.0.1:4040/api/tunnels` にアクセスします
以下のような json が返ってきます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102797/1a818499-3c90-e0e1-4bbb-3393c703e4d9.png)
(ngrokを再起動したので先ほどとURLと変わっていることがわかると思います)

`jq`を使って必要な情報を取り出します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102797/ca7314ac-0424-895a-7a0c-5112e04f56d0.png)
`https://ac69-133-106-36-148.ngrok.io`が無事取り出せました

しかし、ここで一つ罠が
[ngrok](https://ngrok.com/)のURLは`http`と`https`があるのですが、
jsonでの出現順番が不定なので、`.tunnels[0].public_url` だと `http` が取れてきてしまうことがあるのです

ここは単純に `http:` を `https:` に置換することにします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102797/6807b0e4-1419-545a-2206-cbde96b1b977.png)
Webhook設定に利用したいので、変数として保持しておきます
```shell
pi@raspberrypi:~/sidecar/mylinebot $ URL=`curl -s localhost:4040/api/tunnels | jq -r ".tunnels[0].public_url" | sed -e s/http:/https:/`
pi@raspberrypi:~/sidecar/mylinebot $ echo $URL
https://ac69-133-106-36-148.ngrok.io
```

## 3. スクリプトで自動化する

1と2を組み合わせたスクリプトをつくリます
`start_ngrok.sh`という名前で保存しておくと便利です
```sh
#!/bin/sh

# configration
TOKEN={LINE の CHANNEL ACCESS TOKEN}
PORT=3000

# ngrok
nohup ./node_modules/ngrok/bin/ngrok http $PORT &
sleep 5

# ngrok URL
URL=`curl -s localhost:4040/api/tunnels | jq -r ".tunnels[0].public_url" | sed -e s/http:/https:/`

# LINE Webhook
curl -X PUT -H "Authorization: Bearer ${TOKEN}" -H 'Content-Type:application/json' -d '{"endpoint":"'"${URL}"'"}' https://api.line.me/v2/bot/channel/webhook/endpoint

echo $URL
```

ちなみに `nohup` で起動した [ngrok](https://ngrok.com/) の止め方は以下です
```shell
$ ps aux | grep ngrok | grep -v grep | awk `{ print "kill -9", $2 }' | sh
```

以上です
ご参考になれば！

# 参考になる記事

LINE BOTを作りたい、[ngrok](https://ngrok.com/)って何？という方にはこちらの記事が参考になると思います
自分もこの記事を見ながらBOTを作りました

■ Qiita
1時間でLINE BOTを作るハンズオン
https://qiita.com/n0bisuke/items/ceaa09ef8898bee8369d

■ Qiita
LINEでラズパイさんから家の温度を教えてもらう
https://qiita.com/kohbis/items/feeb91727e1bcbd4f092

EOF