はじめてのVPS 入門 Vultr Rails6

## はじめに

[はじめてのVPS 入門 Vultr deploy から destroy　まで](https://qiita.com/may88seiji/items/5f3020329a869f0e3fea)　にてServerを立ち上げるところまで紹介しました。（VPSについてはこのリンクを参照してください）
今回は **Rails 6** を動かすところまで書きたいと思います。
参考になりましたら、下記利用していただけると励みになりますmm

<a href="https://www.vultr.com/?ref=7472934"><img src="https://www.vultr.com/media/banner_2.png" width="468" height="60"></a>
＊紹介バナーになっています。紹介者と新規ユーザー（$10以上のデポジットと30日以上利用することが条件）の双方が得します
（現在、8名の方に利用していただいてます。ありがとうございますmm）

## 対象の読者
```
- Rails で作ったアプリケーションをデプロイしたい方
- AWSなどより安く運用したい方
- Herokuなどより自由度をあげて使いたい方
- VPS にて、一から構築してインフラの勉強したい方
```

## 環境
```
Rails 6.0.2.2
ruby 2.7.0p0
node v10.16.0
mysql 5.7.29
nginx 1.14.1
```

## Deploy New Instance まで
該当ページ https://my.vultr.com/deploy/
画像付きでみたい場合はこちらを参照→[はじめてのVPS 入門 Vultr deploy から destroy　まで](https://qiita.com/may88seiji/items/5f3020329a869f0e3fea)

- Choose Server
 
そのまま `Cloud Compute` を選択

- Server Location

`Tokyo` を選択。
`$3.50/mo` を選びたい場合は `NewYork(NJ)`を選択してください。

- Server Type
64 bit Os
`CentOs` を選択

- Server Size
 
お好きなの選択してください。

- Additional Features

お好きなの選択してください。

- Startup Script

`Add New`を選択してscript欄に下記貼り付けてください。（変更部分あり）
Name はご自由に、TypeはそのままBootで大丈夫です。

```
# 基本的なパッケージ導入
yum -y update
yum -y install tmux vim git gcc gcc-c++ openssl-devel readline-devel libxml2-devel libxslt-devel

# 一般ユーザー作成&設定
useradd webapp
echo '{変更部分 your_pass}' | passwd webapp --stdin
usermod -G wheel webapp
echo '%wheel        ALL=(ALL)       NOPASSWD: ALL' > /etc/sudoers.d/wheel

chmod a+x ~webapp
mkdir -p ~webapp/.ssh
cp ~/.ssh/authorized_keys ~webapp/.ssh/
chmod 700 ~webapp/.ssh
chmod 600 ~webapp/.ssh/authorized_keys
chown -R webapp:webapp ~webapp/.ssh

# SSHサーバー設定
SSHD_CONFIG_FILE='/etc/ssh/sshd_config'
cp ${SSHD_CONFIG_FILE} ${SSHD_CONFIG_FILE}.org

sed -i -e "s/^#Port 22/Port {変更部分 65432}/g" ${SSHD_CONFIG_FILE}
sed -i -e "s/^#PermitRootLogin yes/PermitRootLogin no/g" ${SSHD_CONFIG_FILE}
sed -i -e "s/^#PubkeyAuthentication yes/PubkeyAuthentication yes/g" ${SSHD_CONFIG_FILE}
sed -i -e "s/^PasswordAuthentication yes/PasswordAuthentication no/g" ${SSHD_CONFIG_FILE}
systemctl reload sshd

# FW設定
firewall-cmd --add-service=http --zone=public --permanent
firewall-cmd --add-service=https --zone=public --permanent
firewall-cmd --add-port={変更部分 65432}/tcp --zone=public --permanent
firewall-cmd --remove-service=ssh --zone=public --permanent
firewall-cmd --reload

# ロケール設定
localectl set-locale LANG=ja_JP.utf8
source /etc/locale.conf

# タイムゾーン設定
timedatectl set-timezone Asia/Tokyo

# Redis
yum -y install redis

# Nginx
yum -y install nginx
```
`Update Script` で保存

#### script 解説
- `useradd webapp` → webapp にしていますが、お好きな `user` を設定できます。
- `echo '{変更部分 your_pass}'` はパスワードになります。任意のPWを設定してください。
ex `echo 'echo 'c2cZALBfh5zpcmDk77' | passwd webapp --stdin`

- `sed -i -e "s/^#Port 22/Port {変更部分 65432}/g" ${SSHD_CONFIG_FILE}`
→ sshログインするポートをデファルトから変更します。（もちろんセキュリティ上の理由なので知られないようにしてください。）
ex ` "s/^#Port 22/Port 65432/g" `

- `firewall-cmd --add-port={変更部分 65432}/tcp --zone=public --permanent`
同様に変更してください。
ex `firewall-cmd --add-port=65432/tcp --zone=public --permanent`

Startup Script　にこれらを記述することで、deploy後に下記完了した状態になります。そのままsshログインすることができるので便利です。
- 基本的なパッケージ導入
- user の作成
- SSHサーバーの設定 
- firewallの設定
- ロケール設定
- タイムゾーン設定
- Redis,Nginxのインストール

カスタマイズしたい場合はコマンドを調べたり、scriptなしでログインして試してみてください。

- SSH Keys
- 
`Add New` から自身のPCのSSH key を登録してください。そのままsshログインするために必要です。
`SSH key`とは？とという方は是非、Qiitaで調べてみてください。

これらが完了しましたら `Deploy New` を押してください。

※ デプロイが完了して、さらにsshログインできるようになるまではしばし時間がかかります。
下記メッセージが出た場合は少し待ちましょう。

```
ssh: connect to host {your_ip} port {your_port}: No route to host
```

## SSHログインする

`Server Information` にて `IP Address` をコピーします。
![スクリーンショット 2020-04-20 2.08.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154186/15bd534a-1287-270b-a8b5-e17f941882f2.png)

ターミナルにて
`ssh -A {your_user}@{your_ip_address} -p {your_port}` を打ちます。
ex `ssh -A webapp@207.148.95.156 -p 65432`

`-A` は 認証エージェントを転送する（1つ目のサーバに接続後、続けて別のサーバに接続する際に、最初に使った秘密鍵をそのまま使用する）オプションです。
sshログイン後の質問は `yes` で大丈夫です。

## nodeインストール

```
git clone https://github.com/riywo/ndenv ~/.ndenv
echo 'export PATH="$HOME/.ndenv/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(ndenv init -)"' >> ~/.bash_profile
source ~/.bash_profile
git clone https://github.com/riywo/node-build.git ~/.ndenv/plugins/node-build
ndenv install v10.16.0
ndenv rehash
ndenv global v10.16.0

node -v
```
`v10.16.0` の部分は自身の環境のversionを設定ください。
`node -v` で表示されたら成功です。

## rbenvインストール
```
git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
source ~/.bash_profile
git clone git://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
cd ~/.rbenv/plugins/ruby-build
sudo ./install.sh

rbenv -v
```
`rbenv -v` で表示されたら成功です。

## rubyインストール
```
sudo yum -y install bzip2 make
rbenv install 2.7.0
rbenv global 2.7.0
gem update --no-document

ruby -v
```
ご自身の環境のversionを設定ください。
`node -v` で表示されたら成功です。
※ ruby のインストールは時間かかります。

## railsインストール
```
gem cleanup
gem install rails --no-document

rails -v
```
`rails -v` で表示されたら成功です。

## MySQL インストール
```
sudo yum -y remove mariadb-libs
sudo yum localinstall http://dev.mysql.com/get/mysql57-community-release-el7-7.noarch.rpm
sudo yum -y install mysql-server
```
上記でもインストールできるのですが、mysql の 8がインストールされます。
自分の場合は5.7を利用したかったので、[CentOS 8 に MySQL 5.7 をインストールする](https://mattintosh.hatenablog.com/entry/20200311/1583904463)を参考にしました。
8以外を使いたい方は参照してみてください。

## MySQL設定
```
sudo systemctl start mysqld.service
sudo systemctl status mysqld.service

#デフォルトのパスワードを確認
sudo cat /var/log/mysqld.log | grep "A temporary password is generated"

mysql_secure_installation

# Enter password for user root: => デフォルトのパスワードを入力
# New password: => your_pass
# Re-enter new password: => your_pass
# Change the password for root ? ((Press y|Y for Yes, any other key for No) : => nを入力
# Remove anonymous users? (Press y|Y for Yes, any other key for No) : => y
# Disallow root login remotely? (Press y|Y for Yes, any other key for No) : => y
# Remove test database and access to it? (Press y|Y for Yes, any other key for No) : => y
# Reload privilege tables now? (Press y|Y for Yes, any other key for No) : => y
```

## MySQL DBセットアップ
mysql ログイン
`mysql -uroot -p{設定したのパスワード}`
ex `mysql -uroot -phogehoge`

```
UNINSTALL PLUGIN validate_password;
CREATE DATABASE {your_database} DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci;
CREATE USER '{your_user}'@'localhost' IDENTIFIED BY '{your_user_pass}';

GRANT ALL PRIVILEGES ON {your_database}.* TO '{your_user}'@'localhost';
FLUSH PRIVILEGES;
```

ex

```
UNINSTALL PLUGIN validate_password;
CREATE DATABASE web_app DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci;
CREATE USER 'web_app'@'localhost' IDENTIFIED BY 'web_app';

GRANT ALL PRIVILEGES ON web_app.* TO 'web_app'@'localhost';
FLUSH PRIVILEGES;
```
`database` `username` `password` は `database.yml`の `production` と一致させてください。 

設定後はroot ではなく、作成したuserでログインできるので確認します。

```
mysql -uweb_app -pweb_app
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| web_app            |
+--------------------+
2 rows in set (0.02 sec)

```

## nginx設定
`sudo vim /etc/nginx/nginx.conf` で編集(vim の使い方は別途検索してください)


```vim
# For more information on configuration, see:
#   * Official English Documentation: http://nginx.org/en/docs/
#   * Official Russian Documentation: http://nginx.org/ru/docs/

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

# Load dynamic modules. See /usr/share/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

http {
    server_names_hash_bucket_size 128;
    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  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay        on;
    keepalive_timeout  65;
    types_hash_max_size 2048;

    include            /etc/nginx/mime.types;
    default_type        application/octet-stream;

    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /etc/nginx/conf.d/*.conf;

    upstream app {
      server 127.0.0.1:3000;
    }

    server {
      listen 80;
      server_name {your_domain};
      try_files $uri @app;

      root /home/path/to/public;

      location @app {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_redirect off;
        proxy_pass http://app;
      }
    }


    server {
        listen      80 default_server;
        listen      [::]:80 default_server;
        server_name  _;
        root        /usr/share/nginx/html;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
        }

        error_page 404 /404.html;
            location = /40x.html {
        }

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
    }


# Settings for a TLS enabled server.
#
#    server {
#        listen       443 ssl http2 default_server;
#        listen       [::]:443 ssl http2 default_server;
#        server_name  _;
#        root         /usr/share/nginx/html;
#
#        ssl_certificate "/etc/pki/nginx/server.crt";
#        ssl_certificate_key "/etc/pki/nginx/private/server.key";
#        ssl_session_cache shared:SSL:1m;
#        ssl_session_timeout  10m;
#        ssl_ciphers HIGH:!aNULL:!MD5;
#        ssl_prefer_server_ciphers on;
#
#        # Load configuration files for the default server block.
#        include /etc/nginx/default.d/*.conf;
#
#        location / {
#        }
#
#        error_page 404 /404.html;
#            location = /40x.html {
#        }
#
#        error_page 500 502 503 504 /50x.html;
#            location = /50x.html {
#        }
#    }

}
```
## nginx設定ファイル詳細
一度変更前の設定と上記設定の `diff`（差分） をとってみてください。
それが変更部分になります。
diffは https://difff.jp/ などでとれます。

**主な変更部分**

```
- include /etc/nginx/conf.d/*.conf; 直下　追加
 upstream app {
   server 127.0.0.1:3000;
 }

- 取得したドメインを設定してください。（ドメイン取得については別記事でまとめようと思います。）
server_name {your_domain};

- 参照するpublic配下を設定（ここを変更しないとfaviconなどが読み取れずエラーになります。）
root /home/path/to/public;
```

```
# :wq で保存、再起動、確認
sudo systemctl restart nginx.service
sudo systemctl status nginx.service

# logを見る場合
sudo tail /var/log/nginx/error.log
```
`status` を確認して `active (running) ` と出ればひとまずokです。


## アプリケーションのセットアップ
事前にローカル開発環境で `master.key` をコピーします。

```
cat config/master.key | pbcopy
```

↓ ここから本番開発環境

```
gem install bundler -v 2.1.4
git clone git@github.com:{your_name}/{your_app}.git
bundle install --path vendor/bundle

echo -n '{your_master_key}' > config/master.key
bin/rails db:drop db:create db:migrate db:seed RAILS_ENV=production

bin/rails assets:clobber
bin/rails assets:precompile
RAILS_ENV=production bundle exec puma -d
```

bundler のversionはご自身の環境に合わせてください。
`bundle install`の際、自分は `mysql2` `sassc`のインストールでスタックしました。
下記で解決しましたが、詰まった場合は是非、自身で検索・対応してみてください。

- mysql2

```
sudo yum install mysql-devel
gem install mysql2 -v '0.4.10' --source 'https://rubygems.org/'
```

- sassc
gemfileに追加 

```gemfile
gem 'sassc', '~> 2.1.0'
```

### pumaでおかしいなと思った場合

```
RAILS_ENV=production bundle exec puma
```
で確認ができます。　`-d` がないコマンドですね。 `-d` はなに？と思った方は検索してみてください。

## 本番反映

```
$ cd path/to/app
$ git pull origin master

# DBマイグレーション（必要であれば）
$ bin/rails db:migrate RAILS_ENV=production

# フロントエンドアセットのクリア＆コンパイル（必要であれば）
$ bin/rails assets:clobber
$ bin/rails assets:precompile

# アプリケーションサーバーの再起動
$ bin/rails restart
```

以上になります！！！！

### さいごに
以上が vultr にて rails 6を動かすとこまでの流れになります。
mysqlのインストール、設定、nginxの設定、本番反映後にrailsのエラーといろいろと詰まるところがあると思います。
また、正常に完了できても、各ツールのバージョンが変わればこの記事もたちまちスタックするようになると思います。

詰まると正直とてもつらい気持ちになります...
けれど、`logを確認する→原因を調査する→試行錯誤→修正対応` この流れはこの先も変わらないです。
詰まっても是非成長のチャンスととらえてチャレンジしてみてください。
この記事がrails アプリケーション開発の一助となれば幸いですmm