Vultr VPSにCentOS9+Rails 7+MySQL8+nginxをインストールしてCapistrano3でデプロイ

# はじめに
CentOS Stream 9が出たのでRails 7環境を構築して既存アプリのRails、Rubyのバージョンアップと移行をやったので、手順を記録した。[CentOS8での記事](https://qiita.com/NYC-Blue/items/691e673862282df6ddbc)のCentOS9版です。

Vultrの一番安い10GB SSDプランだとCentOS9ではディスクが足りなくなるので25G以上をお勧めします。

激安VPSの[Vultr](https://www.vultr.com/?ref=8478497)で[紹介者からのリンク](https://www.vultr.com/?ref=8478497)経由でアカウント登録すると＄100のクレジットをもらえるので、CentOS7, 8, MySQL 5.7, 8などの組み合わせをいろいろ試しました。このキャンペーンはいつ終わるか分からないので、興味のある方は以下のリンクからアカウント登録してください。あなたはクレジットをもらえるし、私にも多少のクレジットが入るらしいので、Win-Winです。

### [**このリンク**](https://www.vultr.com/?ref=8478497)で＄100もらえます
![スクリーンショット 2020-03-09 午後7.03.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329289/f3fb7f23-feb3-e19f-e0c3-0ee7ff8f6e81.png)

私もリファラー経由でアカウントを作ったので＄100もらえました。これで最初にあれやこれや試すのは無料でできます。
![スクリーンショット 2020-03-09 午後7.17.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329289/527634e5-40b0-1fac-ecc2-6e3fe7db41b5.png)

# 使った環境
サーバOS: CentOS Stream 9
ローカルOS: macOS Monterey Version 12.5.1 (Apple M1)

Ruby 3.1.2 on rbenv
Rails 7.0.3.1
puma 4.3.12
bundler 2.3.21
Capistrano 3.17.1
MySQL 8.0.28

puma 5から --daemon オプションが廃止されてデプロイ時のPuma再起動が面倒臭いのであえてPuma 4を使っている。解決策もあるので時間がある時にPuma5移行をやろうと思う。（今すぐやりたい人は参考記事を参照して下さい。）

# 1. Vultr VPSインスタンス作成
まっさらから作り直そうと思ったので、新しくインスタンスを作成した。以前は東京サーバーは少し高かったのだが、NJと同額になっていたので東京を選択した。

`Startup Script`と`SSH Keys`については過去記事[Vultr VPSにCentOS7, Ruby on Rails 6, Puma, Capistrano3でのProduction環境デプロイ](https://qiita.com/NYC-Blue/items/79621264072685d3e009)の1-(5)を参考にしてください。

![NewInstance001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329289/4eb17856-5225-3188-7884-3a333f6f0ee3.png)

![NewInstance002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329289/28c2b77c-d472-9258-9346-ee234f06d243.png)

![NewInstance003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329289/9670d6da-d9c9-1b7a-5cbe-4226474079f9.png)




# 2. ログインアカウントの作成
赤で囲ったアイコンでコンソールにアクセスできるので、自動設定されたrootユーザーのパスワードでログインする。基本的にインターネットに接続されているので、OSがインストールされた直後からDefaultのセキュリティホールを突こうとするハッキング攻撃が始まっているので、一番最初にセキュリティ設定をしてから他の作業をすること。

![NewInstance004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329289/5b37dc87-de99-9537-120c-b3c0bfa1418c.png)

## (1) コンソールログイン

![NewInstance005.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329289/67dd2e7a-478d-5c6d-3b29-dfdb5c2d009c.png)

## (2) 後でCapistranoで使うアカウントを追加します。

```ruby:Vultrのコンソール
# adduser deploy
# passwd deploy
# gpasswd -a deploy wheel
# mkdir /home/deploy/.ssh
# chmod 700 /home/deploy/.ssh
# vi /home/deploy/.ssh/authorized_keys
> 公開鍵を貼り付ける（Macで作った/Users/あなた/.ssh/vultr.pubの中身を貼り付けます。）

# chmod 600 /home/deploy/.ssh/authorized_keys
# chown -R deploy:deploy /home/deploy/.ssh/
```

## (3) SSHでログインできるか確認する。
初回だけエラーが出ますが以下のようにyesと入れれば次回からは出ません。web consoleはHTTPSを有効化していないとパスワードが平文で流れてしまうので使いません。

```ruby:Macのターミナル
$ ssh -i ~/.ssh/vultr2 deploy@1あなたのVPSのIPアドレス
The authenticity of host 'あなたのVPSのIPアドレス (あなたのVPSのIPアドレス)' can't be established.
ED25519 key fingerprint is SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxx
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'あなたのVPSのIPアドレス' (ED25519) to the list of known hosts.
Activate the web console with: systemctl enable --now cockpit.socket

[deploy@hogehoge ~]$ 
```

# 2. OSの設定
## (1) SSHDの構成

```ruby:VPSにログインして作業
$ sudo vi /etc/ssh/sshd_config

> 以下を変更
PermitRootLogin no         # rootのリモートログインを不許可
PasswordAuthentication no  # パスワード無しでSSHログイン
ClientAliveInterval 10     # SSHがタイムアウトしないように10秒毎にAlive確認
ClientAliveCountMax 6      # 上記を最大6回（つまり60秒）繰り返す

> 変更を反映
$ sudo systemctl reload sshd
```

ローカルマシンからパスワード無しでSSHログイン

```ruby:Macのターミナル
$ ssh -i ~/.ssh/vultr deploy@あなたのVPSのIPアドレス
```

rootでのリモートログインはできない事を確認する。

```ruby:Macのターミナル
$ ssh -i ~/.ssh/vultr root@あなたのVPSのIPアドレス
root@あなたのVPSのIPアドレス: Permission denied (publickey,gssapi-keyex,gssapi-with-mic).
```

もし、間違ってリモートからSSHできなくなってしまった時は`View Console`アイコンをクリックしてコンソールを出してrootでログインし、復旧させる。

## (2) sudoの設定
deployユーザーにパスワードなしでsudoコマンドを実行できるように設定しました。お好みで設定しても、しなくても良いと思います。

(1)visudoコマンドでsudo権限を付与します。

```ruby:visudoを実行
$ sudo visudo
```

```ruby:visudo
## Allow root to run any commands anywhere
root    ALL=(ALL)       ALL
deploy  ALL=(ALL)       ALL  <=この行を追加

## Same thing without a password
# %wheel        ALL=(ALL)       NOPASSWD: ALL
%deploy         ALL=(ALL)       NOPASSWD: ALL  <=この行を追加
```

deployグループのユーザーはパスワード無しでsudoできます。

```ruby:一応確認
[deploy@vultr ~]$ sudo whoami
root
```

パスワードを聞かれずに`whoami`できました。

## (3) Firewallの設定

```ruby:VPSにSSHログインして作業
$ sudo yum remove -y firewalld
$ sudo yum install -y iptables-services
$ sudo systemctl start iptables
$ sudo systemctl enable iptables
$ sudo /usr/libexec/iptables/iptables.init save
$ sudo vi /etc/sysconfig/iptables

> Web用に８０と433をあける。
# Generated by iptables-save v1.4.21 on Tue Mar 10 01:44:41 2020
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [17:1954]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT  <=この行を追加
-A INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT  <=この行を追加
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
# Completed on Tue Mar 10 01:44:41 2020

> 上記の変更を反映させます。
$ sudo systemctl reload iptables
```

## (4) Swap領域の設定
今回作成したインスタンスはメモリが1GBと少なく、メモリを多く必要とするRailsではメモリ不足になる可能性が高いので、Swap領域を設定します。ページングが多発するとパフォーマンスが悪くなりますが、その際はVultrのプランをUpgradeすれば良いです。（ただし、一度UpgradeするとDowngradeはできません。）　今回は4GBと多めにSwap領域を確保します。

DefaultでSwapファイルが作成されているので一旦Swapを停止させて削除します。

```ruby:rootにsuして実行
[deploy@vultr ~]$ su
Password: 
[root@vultr deploy]# swapoff /swapfile
[root@vultr deploy]# rm /swapfile
rm: remove regular file '/swapfile'? y
```

Swapファイルを作成してSwap領域にします。

```ruby:root実行
[root@vultr deploy]# dd if=/dev/zero of=/swapfile bs=1M count=4096
4096+0 records in
4096+0 records out
4294967296 bytes (4.3 GB, 4.0 GiB) copied, 12.6042 s, 341 MB/s
[root@vultr deploy]# mkswap /swapfile
mkswap: /swapfile: insecure permissions 0644, fix with: chmod 0600 /swapfile
Setting up swapspace version 1, size = 4 GiB (4294963200 bytes)
no label, UUID=b0a8ad95-0d26-4a3f-933b-911a840d7caf
[root@vultr deploy]# swapon /swapfile
swapon: /swapfile: insecure permissions 0644, 0600 suggested.
[root@vultr deploy]# chmod 0600 /swapfile
[root@vultr deploy]# vi /etc/fstab

> 以下が一番下に無い場合は追加します。
/swapfile swap swap defaults 0 0

> /etc/fstabの変更を保存したら、自動マウントされるか試すためにサーバを再起動する。
[root@vultr deploy]# reboot
```

再起動後、`top`コマンドでSwap領域を確認。

```
[deploy@vultr ~]$ top

top - 02:08:14 up 0 min,  1 user,  load average: 0.07, 0.03, 0.01
Tasks: 117 total,   1 running, 116 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
MiB Mem :    956.5 total,    674.2 free,    267.8 used,    157.1 buff/cache
MiB Swap:   4096.0 total,   4096.0 free,      0.0 used.    688.7 avail Mem 
```

# 3. MySQL8.0のインストール
DBはお好きなものを使えば良いと思いますが、MySQL8が5.7の2倍速いらしいので、8.0を使います。

## (1)　MySQLインストール
DefaultでMariaDBが入っている場合はアンインストールしてからMySQLをインストールします。東京のVultrのCentOS9には入ってませんでした。

```ruby:MariaDBがインストールされているか確認
[root@vultr deploy]# yum list installed | grep maria
[root@vultr deploy]# yum list installed | grep Maria
```


```ruby:mysqlをインストール
[root@vultr deploy]# yum install mysql
Last metadata expiration check: 1:34:06 ago on Mon 05 Sep 2022 01:09:18 AM UTC.
Dependencies resolved.
=======================================================================================================================================================================
 Package                                             Architecture                    Version                                  Repository                          Size
=======================================================================================================================================================================
Installing:
 mysql                                               x86_64                          8.0.28-1.el9                             appstream                          2.6 M
Installing dependencies:
 mariadb-connector-c-config                          noarch                          3.2.6-1.el9                              appstream                           11 k
 mysql-common                                        x86_64                          8.0.28-1.el9                             appstream                           75 k

Transaction Summary
=======================================================================================================================================================================
Install  3 Packages

Total download size: 2.7 M
Installed size: 59 M
Is this ok [y/N]: y
Downloading Packages:
(1/3): mariadb-connector-c-config-3.2.6-1.el9.noarch.rpm                                                                               466 kB/s |  11 kB     00:00    
(2/3): mysql-common-8.0.28-1.el9.x86_64.rpm                                                                                            1.5 MB/s |  75 kB     00:00    
(3/3): mysql-8.0.28-1.el9.x86_64.rpm                                                                                                    13 MB/s | 2.6 MB     00:00    
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
Total                                                                                                                                  5.0 MB/s | 2.7 MB     00:00     
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Preparing        :                                                                                                                                               1/1 
  Installing       : mariadb-connector-c-config-3.2.6-1.el9.noarch                                                                                                 1/3 
  Installing       : mysql-common-8.0.28-1.el9.x86_64                                                                                                              2/3 
  Installing       : mysql-8.0.28-1.el9.x86_64                                                                                                                     3/3 
  Running scriptlet: mysql-8.0.28-1.el9.x86_64                                                                                                                     3/3 
  Verifying        : mariadb-connector-c-config-3.2.6-1.el9.noarch                                                                                                 1/3 
  Verifying        : mysql-8.0.28-1.el9.x86_64                                                                                                                     2/3 
  Verifying        : mysql-common-8.0.28-1.el9.x86_64                                                                                                              3/3 

Installed:
  mariadb-connector-c-config-3.2.6-1.el9.noarch                     mysql-8.0.28-1.el9.x86_64                     mysql-common-8.0.28-1.el9.x86_64                    

Complete!
```

```ruby:mysql-serverをインストール
[root@vultr deploy]# yum install mysql-server
Last metadata expiration check: 1:42:23 ago on Mon 05 Sep 2022 01:09:18 AM UTC.
Dependencies resolved.
=======================================================================================================================================================================
 Package                                   Architecture                       Version                                      Repository                             Size
=======================================================================================================================================================================
Installing:
 mysql-server                              x86_64                             8.0.28-1.el9                                 appstream                              16 M
Installing dependencies:
 mecab                                     x86_64                             0.996-3.el9.3                                appstream                             356 k
 mysql-errmsg                              x86_64                             8.0.28-1.el9                                 appstream                             473 k
 mysql-selinux                             noarch                             1.0.5-1.el9                                  appstream                              36 k
 protobuf-lite                             x86_64                             3.14.0-13.el9                                appstream                             232 k

Transaction Summary
=======================================================================================================================================================================
Install  5 Packages

Total download size: 17 M
Installed size: 116 M
Is this ok [y/N]: y
```

## （2）MySQLを構成

```ruby:mysqld起動して次回から自動起動とし、Status確認
[root@vultr deploy]# systemctl start mysqld
[root@vultr deploy]# systemctl enable --now mysqld
Created symlink /etc/systemd/system/multi-user.target.wants/mysqld.service → /usr/lib/systemd/system/mysqld.service.
[root@vultr deploy]# systemctl status mysqld
● mysqld.service - MySQL 8.0 database server
     Loaded: loaded (/usr/lib/systemd/system/mysqld.service; enabled; vendor preset: disabled)
     Active: active (running) since Mon 2022-09-05 02:52:25 UTC; 2min 9s ago
   Main PID: 2636 (mysqld)
     Status: "Server is operational"
      Tasks: 37 (limit: 5877)
     Memory: 430.5M
        CPU: 5.562s
     CGroup: /system.slice/mysqld.service
             └─2636 /usr/libexec/mysqld --basedir=/usr

Sep 05 02:52:17 vultr systemd[1]: Starting MySQL 8.0 database server...
Sep 05 02:52:17 vultr mysql-prepare-db-dir[2559]: Initializing MySQL database
Sep 05 02:52:25 vultr systemd[1]: Started MySQL 8.0 database server.
```

```ruby:MySQLを初期設定
[root@vultr deploy]# mysql_secure_installation

Securing the MySQL server deployment.

Connecting to MySQL using a blank password.

VALIDATE PASSWORD COMPONENT can be used to test passwords
and improve security. It checks the strength of password
and allows the users to set only those passwords which are
secure enough. Would you like to setup VALIDATE PASSWORD component?

Press y|Y for Yes, any other key for No: y

There are three levels of password validation policy:

LOW    Length >= 8
MEDIUM Length >= 8, numeric, mixed case, and special characters
STRONG Length >= 8, numeric, mixed case, special characters and dictionary                  file

Please enter 0 = LOW, 1 = MEDIUM and 2 = STRONG: 0
Please set the password for root here.

New password: 

Re-enter new password: 

Estimated strength of the password: 100 
Do you wish to continue with the password provided?(Press y|Y for Yes, any other key for No) : y
By default, a MySQL installation has an anonymous user,
allowing anyone to log into MySQL without having to have
a user account created for them. This is intended only for
testing, and to make the installation go a bit smoother.
You should remove them before moving into a production
environment.

Remove anonymous users? (Press y|Y for Yes, any other key for No) : y
Success.


Normally, root should only be allowed to connect from
'localhost'. This ensures that someone cannot guess at
the root password from the network.

Disallow root login remotely? (Press y|Y for Yes, any other key for No) : y
Success.

By default, MySQL comes with a database named 'test' that
anyone can access. This is also intended only for testing,
and should be removed before moving into a production
environment.


Remove test database and access to it? (Press y|Y for Yes, any other key for No) : y
 - Dropping test database...
Success.

 - Removing privileges on test database...
Success.

Reloading the privilege tables will ensure that all changes
made so far will take effect immediately.

Reload privilege tables now? (Press y|Y for Yes, any other key for No) : y
Success.

All done! 
```

```ruby:VPS /etc/my.cnf
# vi /etc/my.cnf

> 以下追記
character-set-server = utf8
default_password_lifetime = 0
```

## (3) Railsアプリで使うMySQLユーザーを作成
Railsで使うDBを作り、DBユーザーを作成してGrantします。

```ruby:DB&ユーザー作成
# mysql -u root -p

mysql> CREATE DATABASE あなたのアプリ名_production;
mysql> CREATE USER 'DBユーザ名'@'localhost' IDENTIFIED BY 'パスワード';
mysql> GRANT ALL PRIVILEGES ON あなたのアプリ名_production.* TO 'DBユーザ名'@'localhost';
mysql> FLUSH PRIVILEGES;
mysql> exit;
```


# 4. 環境構築
Ruby、Bundler、その他の必要なパッケージをインストールする。

## (1) Ruby 3.1.2のインストール

```ruby:rootで実行
[root@vultr deploy]# yum groupinstall "Development Tools"
[root@vultr deploy]# yum -y install libyaml-devel
[root@vultr deploy]# yum install -y openssl-devel readline-devel zlib-devel
[root@vultr deploy]# cd /usr/local
[root@vultr deploy]# git clone https://github.com/sstephenson/rbenv.git rbenv
[root@vultr deploy]# git clone https://github.com/sstephenson/ruby-build.git rbenv/plugins/ruby-build


[root@vultr deploy]# vi /etc/profile.d/rbenv.sh

> 以下を記述してパスを通しておく。
export RBENV_ROOT="/usr/local/rbenv"
export PATH="${RBENV_ROOT}/bin:${PATH}"
eval "$(rbenv init --no-rehash -)"

[root@vultr deploy]# source /etc/profile.d/rbenv.sh
[root@vultr deploy]# rbenv install 3.1.2  <=これが時間がかかる。
[root@vultr deploy]# rbenv global 3.1.2
[root@vultr deploy]# rbenv rehash
```

## (2) Budnler 2のインストール

```
[root@vultr local]# gem install bundler
Fetching bundler-2.3.21.gem
Successfully installed bundler-2.3.21
Parsing documentation for bundler-2.3.21
Installing ri documentation for bundler-2.3.21
Done installing documentation for bundler after 0 seconds
1 gem installed
```

## (3) node.js をインストール

```
[root@vultr local]# yum install -y nodejs
[root@vultr local]# node --version
v16.14.0
```

## (4) yarn をインストール

```
[root@vultr local]# npm install -g yarn
```

# 5. Nginxインストール
## (1) yumでインストール

```
[root@vultr local]# yum update
Last metadata expiration check: 2:12:25 ago on Mon 05 Sep 2022 01:09:18 AM UTC.
Dependencies resolved.
Nothing to do.
Complete!
[root@vultr local]# yum info nginx
Last metadata expiration check: 2:12:43 ago on Mon 05 Sep 2022 01:09:18 AM UTC.
Available Packages
Name         : nginx
Epoch        : 1
Version      : 1.20.1
Release      : 13.el9
Architecture : x86_64
Size         : 39 k
Source       : nginx-1.20.1-13.el9.src.rpm
Repository   : appstream
Summary      : A high performance web server and reverse proxy server
URL          : https://nginx.org
License      : BSD
Description  : Nginx is a web server and a reverse proxy server for HTTP, SMTP, POP3 and
             : IMAP protocols, with a strong focus on high concurrency, performance and low
             : memory usage.

[root@vultr local]# yum install yum-utils
[root@vultr local]# yum install nginx
```

## (2) Start Nginx on Centos 8

```ruby:起動
[root@vultr local]# systemctl start nginx
```

```ruby:有効化
[root@vultr local]# systemctl enable nginx
Created symlink /etc/systemd/system/multi-user.target.wants/nginx.service → /usr/lib/systemd/system/nginx.service.
```

```ruby:ステータス確認
[root@vultr local]# systemctl status nginx
● nginx.service - The nginx HTTP and reverse proxy server
     Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled)
     Active: active (running) since Mon 2022-09-05 03:24:17 UTC; 23s ago
   Main PID: 24591 (nginx)
      Tasks: 2 (limit: 5877)
     Memory: 2.0M
        CPU: 28ms
     CGroup: /system.slice/nginx.service
             ├─24591 "nginx: master process /usr/sbin/nginx"
             └─24592 "nginx: worker process"

Sep 05 03:24:17 vultr systemd[1]: Starting The nginx HTTP and reverse proxy server...
Sep 05 03:24:17 vultr nginx[24589]: nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
Sep 05 03:24:17 vultr nginx[24589]: nginx: configuration file /etc/nginx/nginx.conf test is successful
Sep 05 03:24:17 vultr systemd[1]: Started The nginx HTTP and reverse proxy server.
```

一応、基本的なコマンドを書いておきます。OSのバージョンとかで少し違うので。

```ruby:停止
# systemctl stop nginx
```

```ruby:再起動
# systemctl restart nginx
```

```ruby:Config再読込
# systemctl reload nginx
```

NginxはDefault構成でも動作確認できるので、ブラウザにVultr VPSのIPアドレスを入れて確認します。

![スクリーンショット 2022-09-04 午後11.27.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329289/e01e64ad-0ee6-5693-9659-f7ed3b096313.png)

## (3) Nginxの構成
構成ファイルの場所

- Nginx configuration directory: /etc/nginx
- Nginx root directory: /usr/share/nginx/html
- Master/Global configuration file: /etc/nginx/nginx.conf

# 5. Rails環境構築
## (1) Rails 7のための事前準備

```ruby:以下の前提パッケージを入れないとmysql2インストールでエラーになる
# curl https://dl.yarnpkg.com/rpm/yarn.repo > /etc/yum.repos.d/yarn.repo
# dnf --enablerepo=crb -y install ruby-devel rpm-build make gcc gcc-c++ libxml2 libxml2-devel mariadb-devel zlib-devel libxslt-devel nodejs git yarn
# gem install nokogiri -- --use-system-libraries
# gem install webpack
```

```ruby:webpackのインストール(vultr)
$ npm install -D webpack webpack-cli
$ npm audit fix --force
$ npm install css-loader style-loader -D
```

```ruby:macで実行
$ bundle exec rails webpacker:install
```


## (2) Rails 7.0.3.1インストール

```
# gem install rails -v 7.0.3.1
...
Done installing documentation for zeitwerk, thor, method_source, concurrent-ruby, tzinfo, i18n, activesupport, nokogiri, crass, loofah, rails-html-sanitizer, rails-dom-testing, rack, rack-test, erubi, builder, actionview, actionpack, railties, mini_mime, marcel, activemodel, activerecord, globalid, activejob, activestorage, actiontext, mail, actionmailer, actionmailbox, websocket-extensions, websocket-driver, nio4r, actioncable, rails after 51 seconds
35 gems installed
# rails -v
Rails 7.0.3.1
```

## (3) mysql2インストール

```
# gem install mysql2 -- --with-mysql-config=/usr/bin/mysql_config
Building native extensions with: '--with-mysql-config=/usr/bin/mysql_config'
This could take a while...
Successfully installed mysql2-0.5.4
Parsing documentation for mysql2-0.5.4
Installing ri documentation for mysql2-0.5.4
Done installing documentation for mysql2 after 0 seconds
1 gem installed

```

## (2) Test rails app
動作検証用に適当なアプリを作る。Capistranoでローカル環境からデプロイするので適当でOK。

## (1) directory preparation

```
$ sudo su
[root@vultrguest var]# mkdir /var/www
[root@vultrguest var]# mkdir /var/www/myapp
[root@vultrguest var]# chown -R deploy.deploy /var/www
```

## (2) Gemfile preparation

```ruby:deployユーザーで実行
$ cd /var/www/myapp
$ source /etc/profile.d/rbenv.sh
$ bundle init
Writing new Gemfile to /var/www/myapp/Gemfile

$ vi Gemfile
```

```ruby:/var/www/myapp/Gemfile
# frozen_string_literal: true

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

gem "rails"  <= remove "#" here
```

## (3) rails new

```
$ bundle install --path vendor/bundle
$ bundle exec rails new . -B -d mysql --skip-test
       exist  
      create  README.md
      create  Rakefile
      create  .ruby-version
      create  config.ru
      create  .gitignore
      create  .gitattributes
    conflict  Gemfile
Overwrite /var/www/myapp/Gemfile? (enter "h" for help) [Ynaqdhm] Y
$ bundle install --path vendor/bundle

$ rails s
=> Booting Puma
=> Rails 7.0.3.1 application starting in development 
=> Run `bin/rails server --help` for more startup options
Puma starting in single mode...
* Puma version: 5.6.5 (ruby 3.1.2-p20) ("Birdie's Version")
*  Min threads: 5
*  Max threads: 5
*  Environment: development
*          PID: 31178
* Listening on http://127.0.0.1:3000
* Listening on http://[::1]:3000
Use Ctrl-C to stop
```

# 6. Capistrano3でデプロイ
今度はローカルの開発環境で作ったアプリをCapistrano3でデプロイしてみます。

### 前提条件
- GitHubにSSH公開鍵でローカルからPushできていること。


## (1) Vultr VPSにアプリのデプロイ先ディレクトリを準備

```
$ sudo su
# mkdir /var/www
# mkdir /var/www/myapp
# mkdir /var/www/myapp/shared
# mkdir /var/www/myapp/shared/config

# adduser www
# chown -R www:www /var/www
# chown -R deploy /var/www/myapp
# gpasswd -a deploy www
# gpasswd -a nginx www
```

## (2) デプロイ対象外指定したファイルをコピー

```
$ scp -i ~/.ssh/vultr config/master.key deploy@SERVER_IP_ADDR:/var/www/myapp/shared/config/
$ scp -i ~/.ssh/vultr config/database.yml deploy@SERVER_IP_ADDR:/var/www/myapp/shared/config/
```

ここでコピーしたdatabase.ymlのproduction:を編集しておく。

```ruby:/var/www/myapp/shared/config/database.yml
production:
  <<: *default
  database: myapp_production
  username: MySQLに作ったアプリ用ユーザー名
  password: MySQLに作ったユーザーのパスワード
```

## (3) Capistrano関連Config

```ruby:Gemfileに以下を追加
# Use Capistrano for deployment
group :development do
  gem 'capistrano'
  gem 'ed25519'
  gem 'bcrypt_pbkdf'
  gem 'capistrano-rbenv'
  gem 'capistrano-bundler'
  gem 'capistrano-rails'
  gem 'capistrano3-puma'
end
```


#### Capfile, config/deploy.rbを生成

```ruby:ローカル環境のRails_rootで実行
$ bundle exec cap install STAGES=production
```

#### Capfile, config/deploy.rbを設定

```ruby:Capfile
# Load DSL and set up stages
require "capistrano/setup"

# Include default deployment tasks
require "capistrano/deploy"

# Load the SCM plugin appropriate to your project:
#
# require "capistrano/scm/hg"
# install_plugin Capistrano::SCM::Hg
# or
# require "capistrano/scm/svn"
# install_plugin Capistrano::SCM::Svn
# or
require "capistrano/scm/git"
install_plugin Capistrano::SCM::Git

# Include tasks from other gems included in your Gemfile
#
# For documentation on these, see for example:
#
#   https://github.com/capistrano/rvm
#   https://github.com/capistrano/rbenv
#   https://github.com/capistrano/chruby
#   https://github.com/capistrano/bundler
#   https://github.com/capistrano/rails
#   https://github.com/capistrano/passenger
#
# require "capistrano/rvm"
require "capistrano/rbenv"
# require "capistrano/chruby"
require "capistrano/bundler"
require "capistrano/rails/assets"
require "capistrano/rails/migrations"
# require "capistrano/passenger"
require 'capistrano/puma'
install_plugin Capistrano::Puma
install_plugin Capistrano::Puma::Daemon
install_plugin Capistrano::Puma::Nginx

# Load custom tasks from `lib/capistrano/tasks` if you have any defined
Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r }
```

```ruby:config/deploy.rb
# config valid for current version and patch releases of Capistrano
lock "~> 3.12.1"

server 'Your Vultr IP ADDR', port: 22, roles: [:app, :web, :db], primary: true
set :application, 'myapp'
set :repo_url, 'git@github.YOU/myapp.git'
set :user,            'deploy'
set :ssh_options,     {
  forward_agent: true,
  user: fetch(:user),
  keys: %w(~/.ssh/vultr)
}

# Default branch is :master
# ask :branch, `git rev-parse --abbrev-ref HEAD`.chomp

# Default deploy_to directory is /var/www/my_app_name
# set :deploy_to, "/var/www/my_app_name"
set :deploy_to, "/var/www/myapp"

# Default value for :format is :airbrussh.
# set :format, :airbrussh

# You can configure the Airbrussh format using :format_options.
# These are the defaults.
# set :format_options, command_output: true, log_file: "log/capistrano.log", color: :auto, truncate: :auto

# Default value for :pty is false
# set :pty, true

# Default value for :linked_files is []
# append :linked_files, "config/database.yml"

# Default value for linked_dirs is []
# append :linked_dirs, "log", "tmp/pids", "tmp/cache", "tmp/sockets", "public/system"
append :linked_dirs, '.bundle'
append :linked_files, "config/master.key"
append :linked_files, "config/database.yml"
append :linked_dirs, "log", "tmp/pids", "tmp/cache", "tmp/sockets"

# Default value for default_env is {}
# set :default_env, { path: "/opt/ruby/bin:$PATH" }

# Default value for local_user is ENV['USER']
# set :local_user, -> { `git config user.name`.chomp }

# Default value for keep_releases is 5
# set :keep_releases, 5

# Uncomment the following to require manually verifying the host key before first deploy.
# set :ssh_options, verify_host_key: :secure

# rbenv
set :rbenv_type, :system
set :rbenv_ruby, File.read('.ruby-version').strip
set :rbenv_prefix, "RBENV_ROOT=#{fetch(:rbenv_path)} #{fetch(:rbenv_path)}/bin/rbenv exec"

set :bundle_jobs, 2      <=安いプランなので2。Defaultは4。

# debug log level
set :log_level, :debug    <=設定作業中はデバッグモードにした。
```

## (4) nginx-puma連携の事前デプロイ

#### VPS事前準備

```ruby:Vultrで作業
# mkdir /etc/nginx/sites-available
# mkdir /etc/nginx/sites-enabled
# ｃｈｇｒｐ www sites-available
# ｃｈｇｒｐ www sites-enabled
```

#### capistrano-pumaプラグインで設定ファイル自動生成
これらコマンドで、サーバ上の `/etc/nginx/sites-available` と `shared/puma.rb ` に設定ファイルが作られる。

```ruby:ローカル環境のRails_rootで実行
$ bundle exec cap production puma:nginx_config
00:00 puma:nginx_config
      Uploading /tmp/nginx_myapp_production 100.0%
      01 sudo mv /tmp/nginx_myapp_production /etc/nginx/sites-available/myapp_production
    ✔ 01 deploy@Vultr_IP_ADDR 0.200s
      02 sudo ln -fs /etc/nginx/sites-available/myapp_production /etc/nginx/sites-enabled/myapp_production
    ✔ 02 deploy@Vultr_IP_ADDR 0.223s
```

```
$ bundle exec cap production puma:config
00:00 puma:config
      Uploading /var/www/myapp/shared/puma.rb 100.0%
```

#### デプロイ実行
デプロイを実行して、pumaが起動されるところまで正常終了することを確認する。

```ruby:ローカル環境のRails_rootで実行
$ bundle exec cap production deploy
```

#### Tips 1:
GitHubをVultrサーバーから読み込めない場合、ローカル開発環境からGitHubにssh接続する時に使っているSSH鍵を以下のコマンドで追加すると直る。GitHubリポジトリを再作成した場合にエラーになったら試すと良い。

```ruby:localのアプリのディレクトリで実行
ssh-add ~/.ssh/id_rsa
```

#### Tips 2:
OpenSSLのエラーが出た場合、 `config/master.key` で作成された `config/credentials.yml.enc` がデプロイされているか確認する。 `~/.bash_profile` に `export RAILS_MASTER_KEY="abc0123456789xyz..."` があるとRAILS_MASTER_KEYが優先されるので、キーが合わずにこのエラーになる。

#### Tips 3:
`Nginx error: (13: Permission denied) while connecting to upstream`でUnixソケットが使えずにブラウザでアクセスすると502エラーになる場合、通常はNginxの実行ユーザーがDefaultのnginxのままになっていて `/var/www/myapp/shared/tmp/sockets/puma.sock` にアクセスできない事が原因である場合が多い。Nginx workerプロセスの実行ユーザーがnginxではなくdeployになっているか確認する。

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

user deploy;　　　＜＝ここを確認
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

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

events {
    worker_connections 1024;
}

http {
    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 4096;

    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;
    include /etc/nginx/sites-enabled/*;

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

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

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

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

# Settings for a TLS enabled server.
#
#    server {
#        listen       443 ssl http2;
#        listen       [::]:443 ssl http2;
#        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 PROFILE=SYSTEM;
#        ssl_prefer_server_ciphers on;
#
#        # Load configuration files for the default server block.
#        include /etc/nginx/default.d/*.conf;
#
#        error_page 404 /404.html;
#            location = /40x.html {
#        }
#
#        error_page 500 502 503 504 /50x.html;
#            location = /50x.html {
#        }
#    }

}

```

全てのPermission設定が正しいのにこのエラーが出る場合はSELinuxの制限に引っ掛かっている可能性がある。その場合は次を試す。

```
$ sudo setenforce Permissive
```

これでRailsの画面が出た場合はSELinuxのPolicy変更をする。

```
$ sudo grep nginx /var/log/audit/audit.log | audit2allow
$ sudo grep nginx /var/log/audit/audit.log | audit2allow -M nginx
$ sudo semodule -i nginx.pp
$ sudo setenforce Enforcing
```

#### Tips 4:
`Command "webpack" not found.`エラーの対応

```ruby:macのconfig/deploy/production.rbに以下を追加
before "deploy:assets:precompile", "deploy:yarn_install"

namespace :deploy do
  desc 'Run rake yarn:install'
  task :yarn_install do
    on roles(:web) do
      within release_path do
        execute("cd #{release_path} && yarn install")
      end
    end
  end
end
```

#### Tips 5:
`Error: error:0308010C:digital envelope routines::unsupported`エラーでアセットプリコンパイルが失敗する場合の原因はNode.jsがV17になってOpenSSL3を使うようになった為である。これを回避するにはNVM(Node Version Manager)をインストールしてNode.jsのLTSバージョンを使うように設定する。
　なお、私のVultr環境ではnode.jsがV16なのにこのエラーが発生したが、以下の手順でnode.js V16 LTSをインストールしたらエラーは解消された。

```ruby:Step 1: 以下のコマンドでNode Version managerをインストール
[deploy@vultr ~]$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
```

NVMを有効化するために一度ログアウトしてdeplyユーザーでログインしてから以下の続きを実行する。

```ruby:Step 2: 最新安定版のnode.jsをインストール
[deploy@vultr ~]$　nvm install --lts
```

```ruby:Step 3: node.jsがインストールした最新LTSバージョンを使うように設定
[deploy@vultr ~]$　nvm use --lts
[deploy@vultr ~]$ node -v
v16.17.0
```

# 参考記事
[Vultr VPSにCentOS8+Rails 6+MySQL8+nginxをインストールしてCapistrano3でデプロイ](https://qiita.com/NYC-Blue/items/691e673862282df6ddbc)
[Vultr VPSにCentOS7, Ruby on Rails 6, Puma, Capistrano3でのProduction環境デプロイ](https://qiita.com/NYC-Blue/items/79621264072685d3e009)
[CentOS Stream 9 : Install Ruby on Rails 7 - Server World](https://www.server-world.info/en/note?os=CentOS_Stream_9&p=ruby&f=2)
[Nginx error: (13: Permission denied) while connecting to upstream](https://stackoverflow.com/questions/21820444/nginx-error-13-permission-denied-while-connecting-to-upstream)
[Command "webpack" not found.#522](https://github.com/rails/webpacker/issues/522)
[[Solved] error:0308010C:digital envelope routines::unsupported](https://fluentprogramming.com/error-digital-envelope-routines-unsupported/)
[Puma を systemd のユーザーサービスとして起動する](https://engineering.mobalab.net/2021/11/08/puma-as-systemd-user-service/)