As the title says. There are many articles about LINEBot in various languages, but as far as I can find, almost all of them are based on the assumption that they will run in a PaaS environment such as Heroku. In this article, I will describe how to operate in your own environment without using Heroku etc.
See the figure below. Flask Web application development framework for Python. Although it has a function as a Web server, it is for minimum operation check. A separate web server is required for production operation. Official: https://flask.palletsprojects.com/en/1.1.x/ uWSGI WSGI is an abbreviation for Web Server Gateway Interface, which connects a web server and an application. Python-specific specifications. uWSGI is a server that meets this specification, and this time it plays the role of connecting Flask applications and Nginx, which will be described later. It is also an application server that runs Flask. Official: https://uwsgi-docs.readthedocs.io/en/latest/ Nginx Web server. Receives a request from a client and returns a response to it. Since the LINE server is sandwiched between the client and the client this time, the request will be received from the LINE server. Since LINE Bot requires that the Web server be SSL-enabled, it is also necessary to obtain a separate domain and SSL certificate (Oreore certificate is not possible). Official: https://nginx.org/en/
A place that communicates directly with the client's LINE app. Make various settings from the browser on the console called LINE Developers.
www.example.com
)It is OK if you set according to Official Reference Previously, I was asked to set up a plan here (free plan or paid), but as of May 2020, I have not been asked. Moreover, the PUSH API, which should not have been available in the free plan, has become available before I knew it. .. ..
Make settings on the LINE Developers console. This is also OK if you set according to Official Reference You don't have to enter the Bot server endpoint URL yet at this point. The important points here are as follows
First, install Flask, line-bot-sdk, uWSGI
$ pip install flask
$ pip install line-bot-sdk
$ pip install uwsgi
Created under the line_bot directory with the following configuration. The configuration file is a separate file, but I wonder if I like it here
line_bot
|-app.py
|-conf.json
|-logging.conf
app.py Created by referring to sample program of line-bot-sdk-python. When the user sends text, it returns a parrot, and when an image, video, or stamp is sent, it returns a fixed phrase.
app.py
# -*- coding: utf-8 -*-
from flask import Flask, request, abort
from linebot import (
LineBotApi, WebhookHandler
)
from linebot.exceptions import (
InvalidSignatureError
)
from linebot.models import (
MessageEvent, TextMessage, ImageMessage, VideoMessage, StickerMessage, TextSendMessage
)
import os
import sys
import json
from logging import getLogger, config
app = Flask(__name__)
ABS_PATH = os.path.dirname(os.path.abspath(__file__))
with open(ABS_PATH+'/conf.json', 'r') as f:
CONF_DATA = json.load(f)
CHANNEL_ACCESS_TOKEN = CONF_DATA['CHANNEL_ACCESS_TOKEN']
CHANNEL_SECRET = CONF_DATA['CHANNEL_SECRET']
line_bot_api = LineBotApi(CHANNEL_ACCESS_TOKEN)
handler = WebhookHandler(CHANNEL_SECRET)
config.fileConfig('logging.conf')
logger = getLogger(__name__)
@app.route("/test", methods=['GET', 'POST'])
def test():
return 'I\'m alive!'
@app.route("/callback", methods=['POST'])
def callback():
# get X-Line-Signature header value
signature = request.headers['X-Line-Signature']
# get request body as text
body = request.get_data(as_text=True)
logger.info("Request body: " + body)
# handle webhook body
try:
handler.handle(body, signature)
except InvalidSignatureError:
abort(400)
return 'OK'
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text=event.message.text))
@handler.add(MessageEvent, message=ImageMessage)
def handle_image(event):
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text="Image"))
@handler.add(MessageEvent, message=VideoMessage)
def handle_video(event):
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text="Video"))
@handler.add(MessageEvent, message=StickerMessage)
def handle_sticker(event):
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text="Sticker"))
if __name__ == "__main__":
#Specify 9999 as the port this time
port = int(os.getenv("PORT", 9999))
#If Flask is executed by default, it will not be exposed to the outside, so specify the IP and port in the run argument.
app.run(host="0.0.0.0", port=port)
conf.json Set the Channel secret and channel access token obtained by LINE Developers. This time I set it to an external file, but I think you can write it directly in app.py
conf.json
{
"CHANNEL_SECRET": "Set Channel secret",
"CHANNEL_ACCESS_TOKEN": "Set channel access token"
}
logging.conf I totally like it.
logging.conf
[loggers]
keys=root
[handlers]
keys=fileHandler
[formatters]
keys=simpleFormatter
[logger_root]
level=INFO
handlers=fileHandler
[handler_fileHandler]
class=handlers.TimedRotatingFileHandler
formatter=simpleFormatter
args=('app.log','MIDNIGHT')
[formatter_simpleFormatter]
format=%(asctime)s %(levelname)s %(message)s
Nginx proceeds as if it were in / etc / nginx /. If you haven't modified the config file, I think it's supposed to read /etc/nginx/conf.d/*.conf and set it. Create linebot.conf under /etc/nginx/conf.d/ and describe the following. Since port 9998 will be used this time, it is necessary to open the port separately.
linebot.conf
server {
listen 9998 ssl;
server_name example.com;
ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
ssl_ciphers ALL:!aNULL:!SSLv2:!EXP:!MD5:!RC4:!LOW:+HIGH:+MEDIUM;
ssl_certificate [Specify the location where the CRT file is placed];
ssl_certificate_key [Specify the location where the key file is placed];
ssl_session_timeout 10m;
location / {
include uwsgi_params;
uwsgi_pass unix:///tmp/uwsgi.sock;
proxy_pass http://127.0.0.1:9999/;
}
}
Once set, restart Nginx
$ sudo systemctl restart nginx
Create uWSGI configuration file uwsgi.ini in the same layer as app.py and describe the following
uwsgi.ini
# uwsgi.ini
[uwsgi]
#wsgi file
wsgi-file=[app.py path]
callable=app
#Permission host:port
http=0.0.0.0:9999
socket=/tmp/uwsgi.sock
module=app
chmod-socket=666
pidfile=/home/[The path where you want to output the pid file]/uwsgi.pid
#If daemonize is specified, it becomes a daemon. Stdout to the specified path/output stderr
daemonize=/[The path where you want to output the log file]/uwsgi.log
After that, if you start uWSGI with the following command, you can access it.
$ uwsgi --ini myapp.ini
To stop it, just kill -QUIT with the PID of uwsgi.pid.
It doesn't matter if it's a browser or curl, so when you visit https://www.example.com:9998/test
, you should get" I'm alive! ".
Once this is confirmed, specify https://www.example.com:9998/callback
as the Webhook URL in LINE Developers and turn on Use webhook.
(The "verify" button at the bottom of the URL input field causes an error for some reason. We are investigating this)
The LINE Bot you created should now work.
--As mentioned above, you can now use the PUSH API that you couldn't use in the free plan before. I think that the range of development has expanded greatly even with the free plan, so I will investigate how to use it --Unsolved the problem that verify of Webhook URL is an error in the console of LINE Developers. Need to handle the request sent from the LINE server at the time of verification exclusively for it? -** 2020/05/13 postscript ** Article investigated about this was written
I haven't written any page that describes the procedure to run LINE Bot using Heroku. In the case of the free frame, Heroku will go to sleep if it does not operate for a certain period of time (about 30 minutes?) The connection times out, which is not very practical. If you are not thinking about introducing a paid plan, you should run it if you have your own environment.
I would appreciate it if you could let me know if there are any mistakes in the information I provided.
Recommended Posts