【初心者向け】UbuntuでRailsアプリを本番環境でデプロイするためのマニュアル

# 本記事の目的

　プログラム（Ruby on Rails）を触ってきたが、そろそろデプロイしてみたいと思ったときに、色々な記事とにらめっこしながら苦労してなんとかデプロイに漕ぎつけたので、もっと簡単にまとめられたものがあればいいなと思い、本記事を作成いたしました。

# 参考記事

たくさん見たのでどれがどれだか覚えていません。

***

 　かなり初心者を意識して本記事を書いたので、Qiita初心者のためにこういうものを書いておきました。

<details><summary>Qiita記事の見方</summary>

+ ファイルを編集する場合
  + 1行目（？）にファイル名が書いてある
  + 2行目（？）からファイルに記述などする内容が書いてある

〇具体例

```txt:ファイル名
ファイルの中身
```

+ コマンドライン（ターミナル・コマンドプロンプトなど）を編集する場合
  + 先頭に$マークがついている
  + コピペするときに$マークを外す必要がある

〇具体例

```
$ echo 'Hello, World'
```
「$」がコマンドラインを表す記号「 echo 'Hello, World'」が入力するコマンド
+ コマンドライン（ターミナル・コマンドプロンプトなど）の出力を見る場合
  + 先頭に$マークがついていない
  + $がついているかどうかで入力するのか、コンピュータからの出力なのかを見分ける

〇具体例

```
$ echo 'Hello, World' <- 自分で入力したコマンド
Hello, World <- コンピュータによる出力結果
```

</details>

***

# 環境
+ サーバー：AWS EC2
+ OS：Ubuntu Server 22.04
+ Rubyのバージョン：3.3.0
+ Railsのバージョン：7.1.3.2
+ その他
  + Unicorn
  + Nginx

# 本文

まずはサーバーのアップデートを行います。面倒なので、一気にコマンドを入力します。

<details><summary>複数のコマンドを実行するための詳細</summary>

```
$ xxx; yyy
```

これで、

```
$ xxx
```
というコマンドと
```
$ yyy
```
というコマンドが順番に実行されます。
他にもこんな例があります。[例](https://news.mynavi.jp/techplus/article/20181126-728704/)

</details>


アップデートコマンドは以下のようになります。

```
$ sudo apt update && sudo apt upgrade -y
```

詳しく解説すると
<dl>
  <dt>　１番目のコマンド</dt>
  <dd>アップデートがないかの情報を探すコマンド</dd>
  <dt>　２番目のコマンド</dt>
  <dd>探してきたアップデートをコンピュータに反映させるコマンド</dd>
</dl>
です。

***

次にRuby（rbenv）をインストールするために必要なパッケージをインストールしたいと思います。
細かく確認したい場合は最後の「-y」オプションを外してください。
```
$ sudo apt install nano libssl-dev libreadline-dev zlib1g-dev git gcc g++ make libyaml-dev libffi-dev -y
```
***

次にrbenvをインストールして、パスを通します。ここも面倒なので、１行でコマンドを入力していきます。
コマンドの詳しい内容が知りたい方は自分で調べてください。

```
$ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv && git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build && echo "# For rbenv" >> ~/.bash_profile && echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile && echo 'eval "$(~/.rbenv/bin/rbenv init -)"' >> ~/.bash_profile && source ~/.bash_profile && which rbenv

```
次にRubyをインストールします。まずはインストールできるRubyのバージョンを確認します。
```
$ rbenv install -l
```
このような出力がされると思います。
```
$ rbenv install -l
3.0.6
3.1.4
3.2.3
3.3.0
jruby-9.4.6.0
mruby-3.3.0
picoruby-3.0.0
truffleruby-24.0.1
truffleruby+graalvm-24.0.1
```
このうちアルファベットがついていないものの中で一番最新のバージョンをインストールします。
```
3.0.6
3.1.4
3.2.3
3.3.0  <-これが最新バージョン
jruby-9.4.6.0  <-ここから先はアルファベットがついているので無視。
mruby-3.3.0
picoruby-3.0.0
truffleruby-24.0.1
truffleruby+graalvm-24.0.1
```
Rubyのインストールを行います。バージョンx.x.xのRubyをインストールするには、
```
$ rbenv install -v x.x.x
```
と入力します。したがって、今回の場合はバージョン3.3.0をインストールしたいので、
```
$ rbenv install -v 3.3.0
```
と入力します。

::: note warn
注意
結構時間がかかりますが、そういうものなので気にしないでください。
:::

※「-v」はなくても大丈夫ですが、進捗状況を見やすいのでつけることをお勧めします。

***

次にインストールしたRubyをコマンドなどで使えるように設定を反映させます。バージョンx.x.xの場合は
```
$ rbenv rehash; rbenv global x.x.x
```
と入力すればよいので、今回の場合は、
```
$ rbenv rehash; rbenv global 3.3.0
```
と入力します。
***
次にgemをアップデートして設定をしていきます。gemというのはRubyのパッケージを管理するシステムのことです。
アップデートのコマンドは、
```
$ gem update --system; gem --version
```
です。gemのバージョンが表示されれば成功です。

続いて、gemの設定をいじります。gemでライブラリーをインストールした際にドキュメントを生成すると時間がかかるので、ドキュメントを生成しない設定にします。
```
$ touch ~/.gemrc && echo "install: --no-document" >> ~/.gemrc && echo "update: --no-document" >> ~/.gemrc && more ~/.gemrc
```

***

次に、MySQLというデータベースをインストールします。
```
$ sudo apt install mysql-server libmysqlclient-dev -y
```
続いて、インストールしたデータベースのパスワードを初期化します。「hoge」というユーザを追加して、root（管理者）とhogeのパスワードを「fuga」にします。rootとhogeのパスワードは同じではなくても大丈夫です。
次のコマンドでSQLファイルを開いて編集します。
```
$ nano set_password.sql
```
```sql:set_password.sql
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'fuga';
CREATE USER 'hoge'@'localhost' IDENTIFIED WITH mysql_native_password BY 'fuga';
GRANT ALL PRIVILEGES ON *.* TO 'hoge'@'localhost';
FLUSH PRIVILEGES;
```
「Ctrl」+Sで保存、「Ctrl」+Xで編集完了となります。
その後、ファイルのアクセス・実行権限を変更してMySQLを強制的に（パスワードなしで）開きます。
```
$ sudo chmod 777 set_password.sql && sudo mysql
```
MySQL上で先ほど作成したset_password.sqlを実行して閉じます。後の操作で邪魔になるし、セキュリティ的にも問題なのでset_password.sqlの削除も行います。
```
mysql> source ./set_password.sql;  /* set_password.sqlを実行するコマンド */
mysql> quit;  /* MySQLを終了するコマンド */
$ rm set_password.sql
```

***

次にyarnをインストールしてから、インストールされたことを確認します。yarnのバージョンが出てきたら成功です。
```
$ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -; echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list; sudo apt update && sudo apt install yarn -y; sudo apt install --no-install-recommends yarn; yarn --version
```

***

次にnpmをインストールします。
```
$ sudo apt install -y npm && sudo npm install n -g && sudo n stable && sudo apt purge nodejs npm -y && sudo apt autoremove -y && exec $SHELL -l
```
npmのインストールが完了したか確認するコマンドを入力します。nodeとnpmのバージョンが出てきたら成功です。
```
$ node -v; npm -v
```

***

次にRailsをインストールします。後の操作で時間がかかったbigdecimalとunicornというgemもこのタイミングでついでにインストールします。
```
$ gem install rails bigdecimal unicorn
```

***

次にGitHubからソースコードをダウンロードします。hogeがGitHubのユーザー名、fugaがリポジトリー（≒メインフォルダ）名です。適切なものに置き換えてください。
※今回は初心者用ということで、認証面を緩くしていますが、本来はもう少し厳しく設定しておいてください。[設定例](https://zenn.dev/hosht/articles/cc4fd7d6732f3d)
```
$ git clone https://github.com/hoge/fuga.git; ls
fuga
```
lsコマンドで<b>表示された</b>フォルダー（今回は「fuga」）に移動します。
```
$ cd fuga
```

***

忘れがちなので、このタイミングで.envファイルを設定しておきます。[補足：.envとは](https://www.airteams.net/media/articles/1991)
```
$ nano .env
```
先ほど設定したMySQLのパスワードを右辺に入力します。
```.env:.env
DB_PASSWORD=fuga
```

***

必要なgemをインストールします。本番環境用のgemのみインストールしたらサーバーのリソース節約になるので、without 'test development'オプションを付けます。
```
$ bundle config set without 'test development'; bundle install
```

***

secret_key_baseの設定をします。これをしないとRailsが動かないので忘れないようにしましょう。
```
$ rm config/credentials.yml.enc; rails credentials:edit
```

***

Railsのデータベースを設定します。

```
$ RAILS_ENV=production rails db:create && RAILS_ENV=production rails db:migrate && RAILS_ENV=production rails db:seed
```

***

必要なWebpackerに必要なパッケージをインストールします。
```
$ yarn add webpack webpack-cli @babel/plugin-transform-object-rest-spread @babel/plugin-transform-private-methods @babel/plugin-transform-private-property-in-object @babel/plugin-proposal-private-methods @babel/core @hotwired/turbo-rails @rails/webpacker
```

***

Webpackerをインストールします。
```
$ RAILS_ENV=production rails webpacker:install
```

***

Webpackerの設定を変更します。
（実はこの辺がよくわかっていません。詳しい方は教えてください。assetのコンパイル時にどうしてもエラーが出てくるがサイトが動くので、「まぁ良いか」の精神でやっています。）
[やってみたこと]()

```
$ nano config/webpack/production.js
```
もともとこのような行があるので、その下に一行追加します。
追加前
```js:config/webpack/production.js
process.env.NODE_ENV = process.env.NODE_ENV || 'production'

const environment = require('./environment')

module.exports = environment.toWebpackConfig()
```
追加後
```js:config/webpack/production.js
process.env.NODE_ENV = process.env.NODE_ENV || 'production'

const environment = require('./environment')
environment.entry.set("main", "./app/javascript/application.js") // この行を追加

module.exports = environment.toWebpackConfig()
```

***

assetsをコンパイルします。
```
$ RAILS_ENV=production rails assets:precompile
```

***

ホームディレクトリに戻ります。
```
$ cd
```

***

nginxをインストールします。
```
$ sudo apt install nginx -y
```

***

nginxの設定を変更してRailsとつなぎます。
まずはサーバーのグローバルIPアドレスを取得します。以下のコマンドで表示される4つの数字（グローバルIPアドレス）をメモしておいてください。後でまた使います。

```
$ curl inet-ip.info
x.x.x.x
```
設定ファイルを編集します。ファイル内の「x.x.x.x」は先ほど出てきた4つの数字に置き換えてください。もし、ドメインを取得している場合は、IPアドレスではなくドメインにしてもかまいません。
```
$ sudo nano /etc/nginx/sites-available/myapp
```

```txt:/etc/nginx/sites-available/myapp
upstream unicorn {
    server localhost:8080;
}
server {
    listen 80;
    server_name x.x.x.x;

    location / {
        proxy_pass http://unicorn;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
```
次にnginxの設定を反映します。
```
$ sudo ln -sf /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/ && sudo systemctl restart nginx
```

***

次にrailsをService化します。hogeのところは適切なユーザー名に、fugaのところはGitHubのリポジトリー名に置き換えてください。

```
$ sudo nano /etc/systemd/system/myapp.service
```
```service:/etc/systemd/system/myapp.service
[Unit]
Description=My Rails App
After=network.target
[Service]
Type=simple
User=hoge
WorkingDirectory=/home/hoge/fuga
ExecStart=/home/hoge/.rbenv/shims/bundle exec unicorn -E production
Restart=always
[Install]
WantedBy=multi-user.target
```

今作ったServiceをサーバーに反映させて状況を確認します。
```
$ sudo systemctl daemon-reload && sudo systemctl enable myapp && sudo systemctl start myapp && sudo systemctl status myapp
```
以下ように、「Active: active (running)」と表示されていれば成功です。
```
● myapp.service - My Rails App
     Loaded: loaded (/etc/systemd/system/myapp.service; enabled; vendor preset: enabled)
     Active: active (running) since Wed 2024-04-17 02:58:01 UTC; 3h 28min ago
   Main PID: 6148 (ruby)
      Tasks: 13 (limit: 1121)
     Memory: 167.5M
        CPU: 3.738s
.
.
.
```

***

最後にコードをバージョンアップしたとき、1コマンドでサーバーに反映させるシェルスクリプトを作成します。

```
$ nano update.sh
```
fugaはgitのリポジトリー名にしてください。
```sh:update.sh
sudo systemctl stop myapp
cd fuga
git pull
RAILS_ENV=production rails db:migrate
RAILS_ENV=production rails assets:precompile
sudo systemctl start myapp
```
update.shの権限を変更して、サーバーを再起動します。
```
$ sudo chmod 777 ./update.sh; sudo reboot
```


***

これでデプロイできるはずです。確認するにはhttp://x.x.x.xにアクセスして下さい。
（x.x.x.xは先ほどメモしてもらったグローバルIPアドレスです。）

***

以上です。お疲れさまでした。
本記事をお読みいただきありがとうございます。