1万人限定に反応してアカウントを作ってしまったので、
とりあえずbotを動かしてみるところまでやってみた

今回のbot環境を構築するにあたってSSL対応と固定IPが必要という2点が悩みどころ

現状トライアルなので、できるだけ安く、できれば無料で環境構築をしたい
ということで、以下の二つを試してみた

AWS Lambda + API Gateway

API Gatewayはデフォルトでhttpsなので
SSLの点では良さそうと最初に思い試してみた
詳細な実装方法はこちらの記事が参考になる
AWS Lambda + API GatewayでLINE BOT APIを叩いてみた

ただし、API GatewayはIPを固定できないので時間が経つと変わってしまう
別途プロキシをEC2なりで立てる必要が出てくるので今回は諦めた

Heroku + fixie

最終的にこの形に落ち着いた
HerokuはSSLにも対応している
さらに、fixieというアドオンを使ってプロキシを挟むことでIPの固定化もできる
しかも最小構成なら無料という素晴らしさ

awsの世界でサーバーレスっていうのも捨てがたいけど、
herokuの場合はnodeとかpyton以外も使える自由度もあるし、
これが今のところ一番良さそうかなと思っている

以下、ruby(sinatra)+HerokuでのLine Bot環境構築手順のメモ

heroku環境を構築する

herokuを利用するのが初めての場合は以下からアカウントを作成
https://www.heroku.com/

続いてherokuをコマンドラインから扱うためのheroku toolbeltをインストール
https://toolbelt.heroku.com/

上記リンクのgetting startに従ってログインから試してみる

$ heroku login
=> 途中でemailとpasswordを要求され、ログインする

とりあえずアプリをデプロイしてみる

$ mkdir firstsample && cd $_
$ heroku create

成功するとgitのURLとサイトURLが出力されるのでサイトURLへブラウザからアクセスしてみる

Heroku | Welcome to your new app!

みたいな文言が出るページが表示される
これでheroku上にアプリを公開する準備が整った

sinatraアプリを作成する

Gemfileを生成

bundle init

Gemfileに書きを追加

gem 'sinatra'

sinatraをインストール

bundle install --path vendor/bundle

シンプルなアプリをapp.rbに記述

# coding: utf-8

require 'sinatra'

get '/' do
  'hello!'
end

ローカルで起動してみる

bundle exec ruby app.rb

ブラウザでアクセス、localhost:4567にアクセス、helloが表示されればOK

アプリをHerokuに公開する

herokuでsinatraを起動するためにProcfileを追加

# Procfile
web: bundle exec ruby app.rb -p $PORT

gitを設定

git init

herokuのリモートリポジトリを設定(heroku createした時に出力されたgitのURL)

heroku git:remote -a xxxxx
# 確認
git remote -v
=> set git remote heroku to https://git.heroku.com/xxxxx.git

gitignore設定

.DS_STORE
*.swp
/Gemfile.lock
/vendor/
/.bundle

作成したファイルをgitにコミット

git add
git commit -m "initial commit"

herokuのリモートリポジトリにpush

git push heroku master

成功すると以下のようなメッセージが表示される

~ 中略 ~
remote:        https://xxxxx.herokuapp.com/ deployed to Heroku
~ 中略 ~

表示されたURLにアクセスして先ほどのhelloが表示されればデプロイ完了

fixieで固定IP対応(プロキシ)

herokuのアドオンを使用する場合は無料のアドオンしか使わなくても最初にクレジットカードの登録が必要になる

こんなエラーメッセージが出る

Please verify your account to install this add-on plan (please enter a credit card) For more information, see https://devcenter.heroku.com/categories/billing Verify now at https://heroku.com/verify

カード情報を登録後以下のコマンドを実行するとアドオンが追加されてIPアドレスが表示される

$ heroku addons:create fixie:tricycle
=> Your IP addresses are xx.xx.xx.xx, xx.xx.xx.xx

表示されたIPアドレスをLINE DevelopersのServer IP Whitelistに追加する

LINE BOTを実装する

最初にLine developersのbotのcallbackURL
herokuで作成したアプリのURLを設定する
サンプルはとりあえずオウム返し

# coding: utf-8

require 'sinatra'
require 'json'
require 'base64'
require 'net/https'
require 'uri'

post '/' do

  channel_secret = "自分のChannel Secret"
  http_request_body = request.body.read
  hash = OpenSSL::HMAC::digest(OpenSSL::Digest::SHA256.new, channel_secret, http_request_body)
  signature = Base64.strict_encode64(hash)
  # requestヘッダを取得
  http_headers = request.env.select { |k, v| k.start_with?('HTTP_')}

  if signature != http_headers["X-LINE-CHANNELSIGNATURE"]
    {status: :error}.to_json
  end

  params = JSON.parse http_request_body

  from = params["result"][0]["content"]["from"]
  text = params["result"][0]["content"]["text"]

  # リクエストヘッダ
  request_headers = {
      "Content-Type" => "application/json",
      "X-Line-ChannelID" => "自分のChannelID",
      "X-Line-ChannelSecret" => channel_secret,
      "X-Line-Trusted-User-With-ACL" => "自分のMID"
  }

  # リクエストボディ
  request_params = {
      "to" => [from],
      "toChannel" => 1383378250, # 固定値
      "eventType" => "138311608800106203", # 固定値
      "content" => {
          "contentType" => 1,
          "toType" => 1,
          "text" => text
      }
  }

  # message send endpoint
  uri = "https://trialbot-api.line.me/v1/events"
  uri_parsed = URI.parse uri

  # ref : https://devcenter.heroku.com/articles/fixie
  _, username, password, host, port = ENV["FIXIE_URL"].gsub(/(:|\/|@)/,' ').squeeze(' ').split
  # fixieのproxy情報とline botのendpoint情報をセット
  http = Net::HTTP.new(uri_parsed.host, uri_parsed.port, host, port, username, password)

  http.use_ssl = true
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE
  http.post(uri_parsed.path, request_params.to_json, request_headers)

  data = {status: 'OK'}
  data.to_json

end

LINE Developers のBot Channelsページの下の方にある
QRを使ってbotをLINEで友達追加してbotに話しかけてみる
botからレスがくれば無事成功

気づいたらLine Botの説明というよりHerokuの使い方説明になってしまった。。。