【未経験向け】CCNA(200-301)とは? NW未経験が1ヶ月で合格した際に使用した魔法の学習教材、サイトを紹介!!!

【チャットボット】Amazon LightsailでBotpress環境を簡単に構築する!

Botpress

Botpressで最近流行りのチャット・ボットを始めてみようと、ローカルへインストールしたりコンテナに立てて遊んだりしていたのですが、どうせなら作ったBotをサービスとしてパブリックに公開したいと思い、サーバ上でBotpressをセットアップしました。

セットアップ手順が若干難しい部分もありましたので、備忘録として、セットアップ手順を残そうと、記事の執筆に至った次第です。

スポンサーリンク

概要

本記事の概要を以下に記載します。

本記事の概要

本番利用(個人利用の範囲)を想定したBotpressの基盤環境を構築します。
また、作成したBotをサービスとして公開する為、安定した運用が目指し、Botpressを導入するサーバには、Amazon Lightsailを採用します。

機能要件

  • 基盤環境
    • サーバはAmazon Lightsailを使用する。
    • OS選定は右記の通り:プラットフォーム「Linux/Unix」、設計図「Nginx」
    • 個人管理の為、コスト面から最低スペックでインスタンスを構築する。
    • DNS管理はLightsailの標準機能であるDNSゾーンではなく、Route53にて行う。
    • 基盤構築に関してはCloudFormationを使用し、スタックによる管理を行う。
  • Botpress
    • チャット・ボットの開発プラットフォームとしてBotpressを使用する。
    • 言語サーバはBotpress社の提供しているサーバを使用する。
    • OS構築はコンソール上にて、コマンド操作で行う。
      ※将来的には、Ansible等の自動化ツールによるOS構築の自動化を目指す

事前準備

本記事の手順を進めるにあたり、事前に以下の要件を満たして多く必要がある。

  • 任意のプロパイダーでドメインを取得済であり、Route53にてパブリックホストゾーンが作成済であること

基盤構築

Lightsailインスタンスの構築

以下のCFnテンプレートを使用し、環境構築を行います。

  • CloudFormationテンプレート
    • lightsail.yml
      Lightsailインスタンスを構築
    • route53.yml
      Route53のパブリックホストゾーンへサブドメインを登録する
CloudFormationテンプレート – lightsail.yml
AWSTemplateFormatVersion: "2010-09-09"
Description:
  "Launch a PJ-chibiBot-Botpress-Service-to-Lightsail"

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Parameters:
          - InstanceName
          - InstanceType
          - ImageType
          - AvailabilityZone
          - SIPName
          
          
# ------------------------------------------------------------#
# Parameters
# ------------------------------------------------------------# 
Parameters:
  PJPrefix:
    Type: "String"
  InstanceName:
    Type: "String"
    Description: "Enter the name of your lightsail instance."
    Default: "<インスタンス名を指定>"
  InstanceType:
    Type: "String"
    Description: "Allowed Lightsail instance type."
    Default: "nano_2_0"
    ConstraintDescription: "Please choose a valid instance type."
  ImageType:
    Type: "String"
    Description: "Allowed Lightsail Images."
    Default: "nginx"
    ConstraintDescription: "Please choose a valid OS image type."
  AvailabilityZone:
    Type: "String"
    Description: "Select the AZ where you want to run the instance."
    Default: "ap-northeast-1a"
  SIPName:
    Type: "String"
    Description: "Enter the name of your lightsail StaticIp"
    Default: "<StaticIPAddressの名前を指定>"
    
    
### Resources ###
Resources:
# ------------------------------------------------------------#
# Lightsail Instace
# ------------------------------------------------------------# 
  # Lightsailインスタンスの作成
  LightsailInstance:
    Type: "AWS::Lightsail::Instance"
    Properties:
      # インスタンスを実行するAZ
      AvailabilityZone: !Ref "AvailabilityZone"
      # 自動スナップショットの作成を有効にする
      AddOns:
        - AddOnType: "AutoSnapshot"
          # デフォルトでは有効にしておく
          Status: "Disabled"
      # 立ち上げるOSイメージ
      BlueprintId: !Ref "ImageType"
      # インスタンスのサイズ
      BundleId: !Ref "InstanceType"
      # インスタンスの名前
      InstanceName: !Ref "InstanceName"
      
      ## Lightsailのファイアウォール設定。 必要に応じて更新してください。
      ## ポートとIPアドレスから許可リストを作成
      ## https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-port.html
      #Port:
      #  AccessDirection: String
      #  AccessFrom: String
      #  AccessType: String
      #  CidrListAliases: 
      #    - String
      #  Cidrs: 
      #    - String
      #  CommonName: String
      #  FromPort: Integer
      #  Ipv6Cidrs: 
      #    - String
      #  Protocol: String
      #  ToPort: Integer
      
      
# ------------------------------------------------------------#
# Lightsail StaticIp
# ------------------------------------------------------------# 
  StaticIP:
    Type: AWS::Lightsail::StaticIp
    Properties: 
      AttachedTo: !Ref LightsailInstance
      StaticIpName: !Ref SIPName
      
      
# ------------------------------------------------------------#
# Output Parameter
# ------------------------------------------------------------# 
Outputs:
### StaticIPAddress ###
  StaticIP:
    Value: !GetAtt StaticIP.IpAddress
    Export:
      Name: !Sub "${PJPrefix}-Lightsail-StaticIP"
loudFormationテンプレート – route53.yml
AWSTemplateFormatVersion: '2010-09-09'
Description: "Launch a PJ-chibiBot-Botpress-Service-to-Route53"

# ------------------------------------------------------------
#  Metadate
# ------------------------------------------------------------
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Parameters:
          - PJPrefix
          - HostedZoneID
          - SubDomain
          
          
# ------------------------------------------------------------
# Input Parameters
# ------------------------------------------------------------
Parameters:
### Project Prefix ###
  PJPrefix:
    Type: String
### Hosted Zone ###
  HostedZoneID:
    Type: String
    Default: '<ホストゾーンのホストゾーンIDを指定>'
  SubDomain:
    Type: String
    Default: '<サブドメイン>.<ドメイン>(例:www.example.com)'
    
    
### Resources ###
Resources: 
# ------------------------------------------------------------
#  Route53
# ------------------------------------------------------------
### Alias ALB ARN ###
  DNSRecord:
    Type: AWS::Route53::RecordSet
    Properties:
      HostedZoneId: !Ref HostedZoneID
      Comment: "Add New RecordSet"
      Name: !Ref SubDomain
      Type: A
      TTL: '300'
      ResourceRecords:
        - { "Fn::ImportValue": !Sub "${PJPrefix}-Lightsail-StaticIP" }

Botpress構築手順

LightsailインスタンスへSSH接続

作成したインスタンスへSSH接続します。

Bitnamiのアプローチタイプを判定

Bitnamiのアプローチタイプを判定します(アプローチA, アプローチB)

$ test ! -f "/opt/bitnami/common/bin/openssl" && echo "Approach A: Using system packages." || echo "Approach B: Self-contained installation."
Approach A: Using system packages.

詳細:https://docs.bitnami.com/aws/faq/get-started/understand-upcoming-changes/

今回はアプローチAでしたので、その前提で以下の手順を実行していきます。

不要なプロセスの停止

nginxにデフォルトで入っている不要なプロセスを停止します。

$ sudo /opt/bitnami/ctlscript.sh stop php-fpm
$ sudo /opt/bitnami/ctlscript.sh stop mariadb
$ sudo mv /etc/monit/conf.d/php-fpm.conf /etc/monit/conf.d/php-fpm.conf.disabled
$ sudo mv /etc/monit/conf.d/mariadb.conf /etc/monit/conf.d/mariadb.conf.disabled
$ sudo gonit reload

Let’s EncriptによるSSL設定

SSL設定を行います。
なぜWebサービスでもないのに、SSL化するのかというと、SSL設定作成したBotをSlackやTeams等と連携する際に、URLがHTTPSであることが求めらる為です。

また、SSL化にあたり、Let’s Encryptのクライアント lego を使用します。

SSL証明書のダウンロード

Let’s Encryptのクライアント legoをダウンロードします。

$ curl -Ls https://api.github.com/repos/xenolf/lego/releases/latest | grep browser_download_url | grep linux_amd64 | cut -d '"' -f 4 | wget -i -
SSL証明書のセットアップ

ダウンロードしたファイルを解凍します。
※本記事では「lego_v4.6.0_linux_amd64.tar.gz

$ tar xvzf lego_v4.6.0_linux_amd64.tar.gz
$ sudo mkdir -p /opt/bitnami/letsencrypt
$ sudo mv lego /opt/bitnami/letsencrypt/lego
SSL証明書のインストール

解凍したlegoを使用してSSL証明書をサーバへインストールします。
まず、nginxを止めます。

$ sudo /opt/bitnami/ctlscript.sh stop nginx

Letsencript(lego)を実行します。
※ 実行中に「Do you accept the TOS? Y/n」と聞かれた際は、「y」と入力して「Enter」して下さい。

# Letsencriptを実行 ※以下の部分を環境に合わせて変更して下さい。
# 貴方のメールアドレス⇒【hoge@example.com】/ サイトのドメイン名⇒【www.example.com、もしくわexample.com】
$ sudo /opt/bitnami/letsencrypt/lego --tls --email="貴方のメールアドレス" --domains="サイトのドメイン名" --path="/opt/bitnami/letsencrypt" run

作成された証明書をセットアップします。
デフォルトの証明書をoldにして、発行した証明書にシンボリックリンクを貼ります。

# デフォルトの証明書をold化
$ sudo mv /opt/bitnami/nginx/conf/bitnami/certs/server.crt /opt/bitnami/nginx/conf/bitnami/certs/server.crt.old
$ sudo mv /opt/bitnami/nginx/conf/bitnami/certs/server.key /opt/bitnami/nginx/conf/bitnami/certs/server.key.old
$ sudo mv /opt/bitnami/nginx/conf/bitnami/certs/server.csr /opt/bitnami/nginx/conf/bitnami/certs/server.csr.old

# シンボリックリンクを作成
$ sudo ln -sf /opt/bitnami/letsencrypt/certificates/サイトのドメイン名.key /opt/bitnami/nginx/conf/bitnami/certs/server.key
$ sudo ln -sf /opt/bitnami/letsencrypt/certificates/サイトのドメイン名.crt /opt/bitnami/nginx/conf/bitnami/certs/server.crt

# 発行した証明書のパーミッションを変更する
$ sudo chown root:root /opt/bitnami/nginx/conf/bitnami/certs/server*
$ sudo chmod 600 /opt/bitnami/nginx/conf/bitnami/certs/server*

nginxを起動します。

$ sudo /opt/bitnami/ctlscript.sh start nginx
証明書の自動更新

Let’s Encriptの証明書有効期限は3ヶ月となっています。
毎月手動で更新するのは面倒なので、自動で証明書を更新してくれるように設定します。

$ sudo mkdir -p /opt/bitnami/letsencrypt/scripts
$ sudo vi /opt/bitnami/letsencrypt/scripts/renew-certificate.sh

shの中身は以下の通りとなっています。

#!/bin/bash

sudo /opt/bitnami/ctlscript.sh stop nginx
sudo /opt/bitnami/letsencrypt/lego --tls --email="自分のメールアドレス" --domains="適用したドメイン" --path="/opt/bitnami/letsencrypt" renew --days 90
sudo /opt/bitnami/ctlscript.sh start nginx

更新スクリプトが、cronで定期実行されるようにします。

$ sudo chmod +x /opt/bitnami/letsencrypt/scripts/renew-certificate.sh
$ sudo crontab -e

末尾に以下コードを追記します。

0 0 1 * * /opt/bitnami/letsencrypt/scripts/renew-certificate.sh 2> /dev/null

スワップ領域の作成

スワップ領域を作成します。(確かデフォルトだとスワップ領域無かったので。。)

スワップ領域の目安としては、メモリの2倍。(ここではメモリ512Mとして、スワップは1GB)

$ sudo dd if=/dev/zero of=/swapfile bs=1M count=1024
$ sudo chmod 600 /swapfile
$ sudo mkswap /swapfile
$ sudo swapon /swapfile
$ sudo vi /etc/fstab

/etc/fstab」末尾に以下のコードを追記します。

/swapfile swap swap defaults 0 0

Botpressのインストール

Botpressをインストールします。
公式のbotpress.comからLinux版バイナリファイルをダウンロードします。
https://botpress.com/download
ダウンロードしたバイナリファイルはWinSCP,Tera TermのSSH SCP等を使用し、サーバ上にアップロードします。

アップロード先はホームディレクトリを指定して下さい。

※本記事では「botpress-v12_26_10-linux-x64.zip

$ pwd
/home/bitnami
$ ls
botpress-v12_26_10-linux-x64.zip

Botpressの起動テスト

アップロードしたバイナリファイルを指定の場所に配置します。

$ mkdir botpress
$ cd botpress
$ unzip ../botpress-v12_26_10-linux-x64.zip

フォアグラウンドでテスト起動してみます。
※初回起動時に圧縮が展開されます

$ ./bp

サイトへアクセスし、nginxのテストページではなく、Botpressの管理画面が表示されることを確認します。
確認後、「ctrl」+「c」で中断します。

Node.jsのインストール

Node.jsのバイナリファイルをインストールします。
※本記事では12.x系を使用します。

$ curl -fsSL https://deb.nodesource.com/setup_12.x | sudo bash -
$ sudo apt-get install -y nodejs

pm2のインストール

RPMパッケージのグローバルインストールを有効化

rpmパッケージをグローバルインストールできるように設定します。

$ mkdir ~/.npm-global
$ npm config set prefix '~/.npm-global'
$ vi ~/.profile

profile」末尾に以下のコードを追記します。

export PATH=~/.npm-global/bin:$PATH
pm2をインストール

pm2をグローバルへインストールして、OS起動時の自動起動を有効化します。

$ source ~/.profile
$ npm i pm2 -g
$ sudo /home/bitnami/.npm-global/bin/pm2 startup

Nginxの設定ファイルをBotpress用に修正する

Nginxの設定ファイルを、Botpress用の設定に差し替える。

$ cd ~/stack/nginx/conf/
$ mv nginx.conf nginx.conf.bitnami
$ sudo vi nginx.conf

nginx.conf」に以下のコードを貼り付けます。


# Based on https://www.nginx.com/resources/wiki/start/topics/examples/full/#nginx-conf
user               daemon daemon;

worker_processes  auto;
error_log         "/opt/bitnami/nginx/logs/error.log";
pid               "/opt/bitnami/nginx/tmp/nginx.pid";

events {
    worker_connections  1024;
}

http {
  # Disable sending the server identification
  server_tokens off;

  # Prevent displaying Botpress in an iframe (clickjacking protection)
  add_header X-Frame-Options SAMEORIGIN;

  # Prevent browsers from detecting the mimetype if not sent by the server.
  add_header X-Content-Type-Options nosniff;

  # Force enable the XSS filter for the website, in case it was disabled manually
  add_header X-XSS-Protection "1; mode=block";

  # Configure the cache for static assets
  proxy_cache_path /tmp/nginx_cache levels=1:2 keys_zone=my_cache:10m max_size=10g
                inactive=60m use_temp_path=off;

  # Set the max file size for uploads (make sure it is larger than the configured media size in botpress.config.json)
  client_max_body_size 10M;

  # Configure access
  log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

  access_log  logs/access.log  main;
  error_log  logs/error.log;

  # Redirect unsecure requests to the HTTPS endpoint
  server {
    listen 80 default;
    server_name  localhost;

    return 301 https://$server_name$request_uri;
  }

  server {
    listen 443 http2 ssl;
    server_name chibibotpress.chibinfra-itech.com;

    ssl_certificate      bitnami/certs/server.crt; 
    ssl_certificate_key  bitnami/certs/server.key;  

    #include  "/opt/bitnami/nginx/conf/bitnami/*.conf";   

    location /status {
      stub_status on;  
      access_log   off;  
      allow 127.0.0.1;  
      deny all;  
    }

    # Force the use of secure protocols only
    ssl_prefer_server_ciphers on;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

    # Enable session cache for added performances
    ssl_session_cache shared:SSL:50m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;

    # Added security with HSTS
    add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload";

    # Enable caching of assets by NGINX to reduce load on the server
    location ~ .*/assets/.* {
      proxy_cache my_cache;
      proxy_ignore_headers Cache-Control;
      proxy_hide_header Cache-Control;
      proxy_hide_header Pragma;
      proxy_pass http://localhost:3000;
      proxy_cache_valid any 30m;
      proxy_set_header Cache-Control max-age=30;
      add_header Cache-Control max-age=30;
    }

    # We need to add specific headers so the websockets can be set up through the reverse proxy
    location /socket.io/ {
      proxy_pass http://localhost:3000/socket.io/;
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "Upgrade";
    }

    # All other requests should be directed to the server
    location / {
      proxy_pass http://localhost:3000;
    }
  }
}

設定を反映させる為、nginxを再起動します。

$ sudo /opt/bitnami/ctlscript.sh restart nginx

Botpressの起動

Botpressを起動する

Botpressサーバーを起動します。
※ 環境変数EXTERNAL_URLで、設定したドメインのURLを与える

$ pwd
/home/bitnami/botpress
$ EXTERNAL_URL=https://サイトのドメイン pm2 start './bp -p'
Botpressの自動起動設定

無事バックグラウンドでBotpressを起動できたかと思いますが、このままではサーバの再起動時など、サーバやpm2が落ちたタイミングでBotpressが停止してしまいます。

なので、pm2によるBotpressの自動起動設定を行います。
詳細①:https://www.yoheim.net/blog.php?q=20170705
詳細②:https://pm2.keymetrics.io/docs/usage/startup/

$ pm2 startup
[PM2] You have to run this command as root. Execute the following command:
      sudo su -c "env PATH=$PATH:/home/unitech/.nvm/versions/node/v14.3/bin pm2 startup <distribution> -u <user> --hp <home-path>

次に、表示されたコマンドをコピーしてターミナルに貼り付けます。

$ sudo su -c "env PATH=$PATH:/home/unitech/.nvm/versions/node/v14.3/bin pm2 startup <distribution> -u <user> --hp <home-path>

最後に、必要なアプリをすべて起動したら、アプリリストを保存して、再起動後に再生成されるようにします。

$ pm2 save

以上で設定は全て完了です。

動作確認

https://サイトのドメイン」 にアクセスして、Botpress管理ツールが開くか確認してください。

以下の管理画面が表示されれば、動作確認は完了です。

まとめ

本記事の内容は、@nakmas(りらいあデジタル株式会社)さんがQiitaで投稿して下さった手順をほぼほぼ丸パクリしたものです。

Lightsailでbotpressを構築する、といった課題に本格的に取り組みたい方は是非記事を参照してみて下さい。

環境は整ったので、今後はBotの作成に、着手していこうと思います。

参考記事

コメント

タイトルとURLをコピーしました