[LINE Bot 開発入門] LINE Bot Serverを作ってみる その1

# はじめに

LINE Botでユーザーの入力と対話をするBotサーバーを開発してみます。BotサーバーとはユーザーがLINEアプリに入力したメッセージを受信してそれに対する処理を行い、ユーザーに応答を返すためのサーバーです

LINE Bot Serverの開発についてこの記事を含めて数回にわたって解説します。今回はLINE Messaging APIを利用してユーザーと対話するシンプルなLINE Botサーバーを構築してみます。この回ではすでにぼくが作ったシンプルなエコーサーバーをAWS EC2上にセットアップしてMessaging APIチャネルとつなげるところまでやります

セットアップするエコーサーバーはこちらに置いてあります
https://github.com/bathtimefish/line-bot-server-example

セットアップには以下が必要です
1. 独自ドメイン
2. AWSアカウント
3. LINE Developersアカウント

# Messaging APIチャネルを作成する

まず[LINE Developers コンソール](https://developers.line.biz/)にログインして任意のプロバイダーを選択し(ない場合は新規作成する)新規チャネル作成で`Messaging API`を選択してください。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61995/ca3a15e7-0f9a-c4f5-0c1d-b963babf364f.png)

必要な情報を入力してMessaging APIチャネルを作成します。チャンネル名は今回`Bot Server Example`としました。チャネルが正常に作成されると次のような画面になります

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61995/b07d2b6b-f2da-d705-e5d6-c241d28f47cb.png)

`Messaging API設定`タブに移動します

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61995/da4b6cc9-0e8a-77f9-ee15-eb40d0a3f085.png)

最下段の`チャネルアクセストークン（長期）`の`発行`ボタンをクリックしてチャネルアクセストークンを生成します。これは`チャネル基本設定`タブ下に記載されているチャネルシークレットとともに後でBotサーバーのセットアップ時に使用します

# EC2 インスタンスをセットアップする

[AWS Management Console](https://aws.amazon.com/jp/console/)でBotサーバー用のEC2インスタンスを立ち上げます。今回は以下のスペックで作成しました。

* Ubuntu Server 20.04 LTS (HVM), SSD Volume Type - ami-03d5c68bab01f3496 (64 ビット x86
* t2.micro
* 汎用SSD 8GB
* セキュリティグループ: インバウンドルール HTTP(TCP 80), HTTPS(TCP 443) を解放

インスタンスが立ち上がったらパブリックIPをRoute53などでドメインを割り当てます。ここでは `line-bot.bathtimefish.com`というドメインを割り当てたことにします

インスタンスにログインし、Ubuntuをアップグレードします

```
sudo apt update && sudo apt upgrade -y
```

node.jsのLTSをインストールします

```
sudo apt install -y nodejs npm && sudo npm i -g n yarn && sudo n lts
```

node.jsの新しいバージョンを反映するためにいったんサーバーからログアウトし、再度ログインします。再ログイン後、node.jsのバージョンを確認します

```
$ node -v
v14.17.4
```

npmも最新にします

```
$ sudo npm i -g npm
$ npm -v
7.20.5
```

# Let’s Encryptを導入する

LINE Botサーバーはhttpsサーバーである必要があるのでLet's Encriptでサーバー証明書を作成します

```
sudo apt install -y certbot
sudo certbot certonly --standalone
```

以降、対話形式でいろいろ聞かれます。まず email アドレスを入力します

```
Enter email address (used for urgent renewal and security notices) (Enter 'c' to
cancel): [あなたのEメールアドレス]
```

`A` を入力します

```
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must
agree in order to register with the ACME server at
https://acme-v02.api.letsencrypt.org/directory
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(A)gree/(C)ancel: A
```

運営元のElectronic Frontier
FoundationにEメールアドレスを共有していいか聞かれます。Yes/Noは任意で

```
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing to share your email address with the Electronic Frontier
Foundation, a founding partner of the Let's Encrypt project and the non-profit
organization that develops Certbot? We'd like to send you email about our work
encrypting the web, EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
(Y)es/(N)o: 
```

サーバーのドメイン名を入力します。上記でインスタンスに割り当てたドメイン名を入力してください

```
Please enter in your domain name(s) (comma and/or space separated)  (Enter 'c'
to cancel): line-bot.bathtimefish.com
```

処理が成功すると以下のようになります。Let's Encriptはポート80を使うのでインバウンドルールで解放しておいてください

```
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for line-bot.bathtimefish.com
Waiting for verification...
Cleaning up challenges

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/line-bot.bathtimefish.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/line-bot.bathtimefish.com/privkey.pem
   Your cert will expire on 2021-11-06. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot
   again. To non-interactively renew *all* of your certificates, run
   "certbot renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le
```

サーバー証明書、秘密鍵はそれぞれ以下のディレクトリに置かれます
`/etc/letsencrypt/live/[ドメイン名]/fullchain.pem`
`/etc/letsencrypt/live/[ドメイン名]/privkey.pem`

これで環境が整いました

# Botサーバーをセットアップする

サンプルのBotサーバーをcloneします

```
git clone https://github.com/bathtimefish/line-bot-server-example
```

Botサーバーのconfigファイルを編集します

```
cd line-bot-server-example
vi src/config.ts
```

`config.ts`は以下のようになっています

```config.ts
import * as line from '@line/bot-sdk';

const lineClientConfig: line.ClientConfig = {
  channelAccessToken: '[CHANNEL ACCESS TOKEN]',
  channelSecret: '[CHANNEL SECRET]',
};

const config = {
  lineClientConfig,
  baseUrl: '[SERVER BASE URL]',
  certFilePath: {
    key: '../cert/privkey.pem',
    cert: '../cert/fullchain.pem',
  }
};

export default config;
```

`[CHANNEL ACCESS TOKEN]`をMessaging APIチャネルで生成したチャネルアクセストークンに、`[CHANNEL SECRET]`をMessaging APIチャネルに記載されているチャネルシークレットに`[SERVER BASE URL]`をBotサーバーのURL(例: `https://line-bot.bathtimefish.com`) に変更してください

Let's Encryptの証明書をコピーしてユーザーを変更します

```
mkdir -p cert
sudo cp /etc/letsencrypt/live/[ドメイン名]/fullchain.pem ./cert/
sudo cp /etc/letsencrypt/live/[ドメイン名]/privkey.pem ./cert/
sudo chown ubuntu:ubuntu ./cert/*.pem
```

必要なモジュールをインストールしてビルドします

```
yarn && yarn build
```

サーバーを起動します

```
sudo yarn start
```

以下のように表示されたら起動成功です

```
Starting LINE Bot Example Server listening at https://0.0.0.0:443
```

Webブラウザで `https://[ドメイン名]` にアクセスすると`Hello LINE Bot server!`と表示されます

# Messaging APIチャネルのWebhookを設定する

LINE Developer Consoleにアクセスして`Bot Server Example
`チャネルの`Messaging API設定`タブに移動し`Webhook設定`の`編集`をクリックします

テキストフィールドに`https://[ドメイン名]/messaging/event`と入力して`更新`ボタンをクリックします

![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61995/71c72b1e-3d20-8ca8-43ec-b78b68f977a5.png)

ここに入力するURLは有効な証明書を持つhttpsでなければならないことに注意してください

Webhook設定が保存された後、`Webhookの利用`トグルをクリックして有効にし`検証`ボタンをクリックします

![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61995/f085c082-1198-41c8-164d-d60a4c019057.png)

URLの検証が成功すると`成功`ダイアログが表示されます。このときBotサーバー側にMessaging APIチャネルから空のイベントが送信されているのが確認できます

![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61995/e339355b-8d85-f755-0d5c-3c40a143871e.png)

```
Starting LINE Bot Example Server listening at https://0.0.0.0:443
Destination: .......
Events: []
```

これでMessaging APIチャネルのWebhookをBotサーバーが受信できるようになりました。LINE Botサーバーの完成です！

# LINEアプリでBotサーバーと対話してみる

LINEアプリでこのBotと友達になり対話をしてみます。`Bot Server Example
`チャネルの`Messaging API設定`タブに表示されているQRコードをLINEアプリの`友達追加`->`QRコード`で読み取ってBotを友だち追加します

追加できると以下のようにBotがはじめましての挨拶をしてくれます

![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61995/be3308b0-d8bd-1e76-78a0-c7d938c3da6b.png)

サーバーのログをみると以下のように`"type": "follow"`のイベントが受信されています

```
Events: [{"type":"follow","timestamp":1628435272899,"source":{"type":"user","userId":"......."},"replyToken":".......","mode":"active"}]
```

LINEアプリでテキストを送信してみます

![11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61995/2792661f-e11a-2202-3be4-60003c399095.png)

送信したメッセージがそのまま返ってきましたが、その前に「個別のお問い合わせを受け付けておりません」というメッセージが送信されます。これはLINE公式アカウントの応答メッセージが有効になっているからです。表示しないようにするには`Bot Server Example
`チャネル->`Messaging API設定`タブ->`LINE公式アカウント機能`下にある`応答メッセージ`の`編集`をクリックします

![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61995/b744567c-0350-8917-7970-15ba603389ff.png)

LINE Offical Account Managerの応答設定画面が開きます。`詳細設定`->`応答メッセージ`をオフにします

![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61995/858b6638-c45a-addd-9222-5af4454691fc.png)

LINEアプリでもう一度テキストを送信してみます

![12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61995/ebfc6185-f472-2c39-ebab-2a34b3bb048b.png)

今度は応答メッセージが表示されません。応答設定では初期の挨拶メッセージのオン/オフや各メッセージのカスタマイズも可能です

# 画像を送信してみる

このBotサーバーはテキストと画像の送信をサポートしています。次はLINEアプリで画像を送信してみます

![13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61995/37fff043-322c-2702-5bbe-e15c46693bfa.png)

画像を送信すると、Botサーバーに画像が送信され保存先URLがテキストメッセージで返ってきます。URLをタップするとBotサーバーに送信された画像を見ることができます

![14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61995/5239d479-6d4a-52f7-dbed-8e31174b8471.png)

サーバーログではメッセージタイプ`image`のイベントが確認できます

```
Events: [{"type":"message","message":{"type":"image","id":"14537939583671","contentProvider":{"type":"line"}},"timestamp":1628435292100,"source":{"type":"user","userId":"......."},"replyToken":".......","mode":"active"}]
```

[LINE Bot SDK](https://github.com/line/line-bot-sdk-nodejs)にはイベントメッセージに対応する画像などのコンテンツデータをBotサーバーにダウンロードする機能が含まれていてこのような処理を簡単に開発することができます

# まとめ

簡単なLINE Botサーバーを立ち上げてLINEアプリで対話することができました。次回はBotサーバーの仕組みを理解するために[line-bot-server-example](https://github.com/bathtimefish/line-bot-server-example)のソースコードを読んでいきます