VPSを借りる [Ruby、Sinatra、Puma、LINE Bot] #5


line-bot-sdk-ruby @LINE Corp

NAME=yourname

LINE_CHANNEL_ID=yourid
LINE_CHANNEL_SECRET=yoursecret
LINE_CHANNEL_TOKEN=yourtoken

DOMAIN=yourdomain

sudo dnf install @ruby ruby-devel make

sudo gem install rubygems-update --no-document --install-dir=/usr/share/gems
sudo gem update --system --no-document
sudo gem install bundler -n /usr/local/bin --no-document
sudo gem list

sudo mkdir /var/www/app
sudo chown -R $NAME: /var/www/app
cd /var/www/app

bundle init

tee -a Gemfile << EOF
gem "nio4r"
gem "sinatra"
gem "puma"
gem 'line-bot-api'
EOF

bundle config set --local path 'vendor/bundle'

bundle install

tee /var/www/app/app.rb << EOF
# app.rb
require 'sinatra'
require 'line/bot'

def client
  @client ||= Line::Bot::Client.new { |config|
    config.channel_id = ENV["LINE_CHANNEL_ID"]
    config.channel_secret = ENV["LINE_CHANNEL_SECRET"]
    config.channel_token = ENV["LINE_CHANNEL_TOKEN"]
  }
end

post '/callback' do
  body = request.body.read

  signature = request.env['HTTP_X_LINE_SIGNATURE']
  unless client.validate_signature(body, signature)
    error 400 do 'Bad Request' end
  end

  events = client.parse_events_from(body)
  events.each do |event|
    case event
    when Line::Bot::Event::Message
      case event.type
      when Line::Bot::Event::MessageType::Text
        message = {
          type: 'text',
          text: event.message['text']
        }
        client.reply_message(event['replyToken'], message)
      when Line::Bot::Event::MessageType::Image, Line::Bot::Event::MessageType::Video
        response = client.get_message_content(event.message['id'])
        tf = Tempfile.open("content")
        tf.write(response.body)
      end
    end
  end

  # Don't forget to return a successful response
  "OK"
end
EOF

sudo tee /etc/sysconfig/linebot.conf << EOF
LINE_CHANNEL_ID="$LINE_CHANNEL_ID"
LINE_CHANNEL_SECRET="$LINE_CHANNEL_SECRET"
LINE_CHANNEL_TOKEN="$LINE_CHANNEL_TOKEN"
EOF

tee config.ru << EOF
require_relative "app"
run Sinatra::Application
EOF

mkdir config

tee config/puma.rb << EOF
require "fileutils"

#root path
app_path = File.expand_path("..", __dir__)
tmp_dirs = ["tmp/pids","tmp/sockets" ,"log"]

tmp_dirs.each do |path|
  mk_path = File.join(app_path, path)
  FileUtils.mkdir_p(mk_path) unless Dir.exist?(mk_path)
end

#default directory
directory app_path
#env mode
environment 'production'

#service daemon
#daemonize

#process id file
pidfile "#{app_path}/tmp/pids/puma.pid"

#puma status file
state_path "#{app_path}/tmp/pids/puma.state"

#stdout, stderr put file
stdout_redirect "#{app_path}/log/app.log", "#{app_path}/log/app_err.log", true

#thread settting low, high
threads 0, 16

#socket type
#bind 'tcp://0.0.0.0:9292' #=> tcp socket
bind "unix:///#{app_path}/tmp/sockets/puma.sock"

#pumactl
activate_control_app
EOF

sudo tee /etc/nginx/conf.d/$DOMAIN.conf << EOF
server {
    listen 80;
    listen [::]:80;

    server_name www.$DOMAIN $DOMAIN;

    include snippets/letsencrypt.conf;

    location / {
        return 301 https://\$host\$request_uri;
    }
}

server {
    listen 443 ssl http2;

    server_name www.$DOMAIN $DOMAIN;

    ssl_certificate /etc/letsencrypt/live/$DOMAIN/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/$DOMAIN/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/$DOMAIN/chain.pem;

    include snippets/ssl.conf;

    root /var/www/$DOMAIN/public_html;

    index index.php;

    access_log /var/log/nginx/$DOMAIN.access.log;
    error_log /var/log/nginx/$DOMAIN.error.log;

    location /app/ {
        rewrite /app/(.*) /\$1 break; 

        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_set_header Host \$http_host;

        proxy_pass http://unix://var/www/app/tmp/sockets/puma.sock;
    }

    location ~ \.php\$ {
        try_files \$uri =404;
        fastcgi_pass unix:/run/php-fpm/www.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name;
        include fastcgi_params;
    }
}
EOF

sudo nginx -t

#sudo cat /var/log/audit/audit.log | grep nginx | audit2allow -m nginx
#sudo cat /var/log/audit/audit.log | grep nginx | audit2allow -M nginx

tee nginx.te << EOF
module nginx 1.0;

require {
        type http_port_t;
        type httpd_sys_content_t;
        type httpd_t;
        class tcp_socket name_connect;
        class sock_file write;
}

#============= httpd_t ==============

#!!!! This avc is allowed in the current policy
allow httpd_t http_port_t:tcp_socket name_connect;
allow httpd_t httpd_sys_content_t:sock_file write;
EOF

sudo checkmodule -M -m -o nginx.mod nginx.te
sudo semodule_package -o nginx.pp -m nginx.mod
sudo semodule -i nginx.pp

sudo tee /etc/systemd/system/puma.service << EOF
[Unit]
Description=Puma Application Server
After=network.target

[Service]
Type=simple
User=$NAME
EnvironmentFile=/etc/sysconfig/linebot.conf
WorkingDirectory=/var/www/app/
ExecStart=bundle exec pumactl start
Restart=always

[Install]
WantedBy=multi-user.target
EOF

sudo chmod +x /etc/systemd/system/puma.service
sudo systemctl enable puma
sudo systemctl start puma
systemctl status puma

sudo systemctl restart puma
sudo systemctl restart nginx


VPSを借りる [VPS、SSH、Nginx] #1
VPSを借りる [HTTPS] #2
VPSを借りる [PHP] #3
VPSを借りる [PostgreSQL] #4