MySQL + Nginx + Puma で Ruby on Rails を AWSにデプロイする



##はじめに

**「Progate の Rails コースを終え、いよいよ自分のアプリをデプロイしてみたい！」**
**「Heroku ではデプロイできたけどAWSはさっぱり...」**

という方に、できるだけシンプルに AWS に Rails をデプロイする手順をまとめました！

(※ 同じような記事は他にも有りますが、Ruby や Rails のバージョンが古かったり、EC2 が AmazonLinux1 だったりして古いので今回の記事を書きました。)

下記のような方におすすめです。

- **簡単なインフラ構成でとりあえずデプロイの感覚をつかみたい。**
- **インフラや AWS が全くわからないがとにかく Rails を公開したい。**
- **できるだけ新しめなバージョンでデプロイしたい。**
  - Ruby 3.0
  - Rails 6.1
  - Web サーバーは Puma + Nginx
  - EC2 は AmazonLinux2

今回は下記のような構成で環境構築をします

![aws_single.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559794/bfeff559-f279-9147-0ea6-04bfd6a42f58.png)

早速進めていきたいですが、気をつけて頂きたいのが、紹介しているコードの中で例えば、

~~~
　/var/www/rails/{アプリ名} 
~~~

などと書いている時がありますが、自分の環境に合わせて

~~~
　/var/www/rails/sample_app
~~~

としてください

~~~
 /var/www/rails/{sample_app} 
~~~

ではないのでご注意


では、スタート！


## 第一章 サーバーの準備

まずはAWSで自分のアプリをデプロイするサーバーを準備します

AWSの設定はかなり複雑で分かりづらいと思うのできるだけシンプルになるようにしました

最初は全く分からないと思いますが、デプロイが出来て感覚が掴めたら追加で色々な設定ができるよう本などでしっかり勉強していくのがいいでしょう

手順を最初にざっと説明すると、

**VPC(AWSの中で自分が使える領域のようなもの)を作成**
↓
**VPCの中にサブネットを作成**
↓
**インターネットゲートウェイとルートテーブルでサブネットを外の世界に繋ぐ**
↓
**セキュリティグループで許可する通信の設定**
↓
**サブネットの中にEC2を作成**

という流れです。

では AWS という広大な海に自分のサーバーを立ててアプリを公開していきましょう！

###1.VPCを作成

- 名前はご自由につけてください(アプリの名前_VPCなど)
- IPv4CIDERブロックは10.0.0.0/16に設定
- あとはデフォルトのままで

###2.サブネットを作成

- 名前はご自由に
- VPCは先程作ったVPCを選択
- IPv4CIDERブロックは10.0.0.0/24に設定

###3.インターネットゲートウェイを作成

- 名前はご自由に
- 作成後は先程作ったVPCをアタッチ

###4.ルートテーブルを作成

- これも名前はご自由に
- 作成後は、ルートの編集で0.0.0.0/0を追加し、<br>ターゲットに先程作ったインターネットゲートウェイを選択し保存
- サブネットの関連付けで先程作ったサブネットを選択
- あとはデフォルトのままで

###5.セキュリティグループを作成

- 名前はご自由に
- 作成後は<br>`タイプ:HTTP ソース:任意の場所(他の設定はデフォルト)`<br>と、<br>`タイプ:SSH ソース:任意の場所(他の設定はデフォルト)`<br>を追加し保存

>- HTTP通信(皆さんが普段Webページをみている時の通信)の設定世界中の人がでサーバーにアクセスきるようになります。
>- SSH通信は自分のパソコンからサーバーにログインし開発を行うための通信です。(自分のIPからしか入れないようにするにはソース:マイIP にしましょう)

- あとはデフォルトのままで

###6.EC2を作成

- EC2インスタンスの作成

 - 無料枠の中からAmazonLinux2を選択
 - ネットワーク:先程作ったVPCを選択
 - サブネット:先程作ったサブネットを選択
 - 自動割り当てパブリックIP:有効化を選択
 - セキュリティーグループ:先程作ったセキュリティグループを選択

- キーペアの登録
 - キーペアファイル(~.pem)を作成します、これを使ってローカル(自分のパソコンのこと)からEC2にログインします
 - キーペアファイル(~.pem)はホームディレクトリ直下の.ssh配下に移動


- ElasticIPの割当て(EC2のパブリックIPアドレスは起動する度に変わってしまうのでElasticIPによって固定します。)
 - ElasticIPを作成
 - 先ほど作ったEC2インスタンスにElasticIPを関連づける



これでサーバーが起動できました。
次の章からはこのサーバーに入って環境構築を行います。



## 第二章 サーバーにログインし環境構築

###1.EC2にログイン

**※ 以下は自分の Mac にて実行**

キーペアファイルのあるディレクトリに移動

~~~
cd ~/.ssh
~~~

キーペアファイルに権限を付与

~~~
chmod 600 {自分のキーペアの名前}.pem
~~~

サーバー(EC２インスタンス)にログイン

~~~
ssh -i {自分のキーペアのpemファイル} ec2-user@{自分のElasticIPアドレス}
~~~

**※ これ以降は EC2 の中にて実行**

ユーザーを作成

~~~

sudo adduser {新規ユーザー名}
#新規ユーザー名の登録 

sudo passwd {新規ユーザー名} 
#パスワードを聞かれるので設定したいパスワードを入力

sudo visudo

~~~

ユーザーの権限の変更

~~~
1.rootに関する権限の記述箇所
root    ALL=(ALL)       ALL　　を探す。
2.その下に、作成したユーザーに権限を追加する記述
{ユーザー名}   ALL=(ALL)       ALL 　を追加する
~~~

ユーザーの切替

~~~
sudo su - {ユーザー名}
~~~

###2.Rubyをインストール

以下Rubyをインストールするための下準備

~~~
sudo yum install -y git gcc gcc-c++ openssl-devel zlib-devel readline-devel
~~~

~~~
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 https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
~~~

~~~
rbenv rehash  
~~~

以下Rubyのインストールです、インストールするRubyのバージョンは自分の環境に合わせてください

~~~
rbenv install -v 3.0.0
~~~

~~~
rbenv global 3.0.0
~~~

~~~
rbenv rehash
~~~

インストールできたか確認

~~~
ruby -v
~~~

###3.MySQL(MariaDB)のインストール

MariaDB をインストール
(※ MariaDB って何だ? って思った方、MariaDB は MySQL と互換性があり普通に MySQL として使えますのでご安心ください。)

インストール

~~~
sudo yum install -y mariadb-server mariadb-devel
~~~

起動

~~~
sudo systemctl start mariadb
~~~

###4.nginxのインストール

インストール

~~~
sudo amazon-linux-extras install nginx1
~~~

###5.node.jsをインストール

~~~
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
~~~

~~~
. ~/.nvm/nvm.sh
~~~

~~~
nvm install node
~~~

###6.Yarnをインストール
~~~
curl -o- -L https://yarnpkg.com/install.sh | bash
~~~

~~~
export PATH="$HOME/.yarn/bin:$HOME/.config/yarn/global/node_modules/.bin:$PATH"
~~~

##第三章 Rails、DB、Webサーバーの設定

###1. GitHub から Rails を持ってくる

`/var/www/rails/` の配下に Rails アプリを持ってくる、以下を一行一行実行していく

~~~
cd / (/ディレクトリに移動)
sudo chown {ユーザー名} var (varフォルダの所有者を{ユーザー名}にする)
cd var (varディレクトリに移動)
sudo mkdir www (wwwディレクトリの作成)
sudo chown {ユーザー名} www (wwwフォルダの所有者を{ユーザー名}にする)
cd www  (wwwディレクトリに移動)
sudo mkdir rails  (wwwディレクトリの作成)
sudo chown {ユーザー名} rails (railsフォルダの所有者を{ユーザー名}にする)
cd rails (railsディレクトリに移動)
~~~

GitHub からクローン

~~~
git clone {自分のRailsのアプリのリポジトリのclone用URL}
~~~

gem をインストール

~~~
cd {自分のアプリ名(ディレクトリ名)}
~~~

~~~
bundle install
~~~
###2. DBの設定
DBとの接続用の設定、以下をRailsアプリ内のconfig/database.ymlに追加
(ymlファイルなのでインデントはスペース2つ分で書くこと。)

~~~config/database.yml

production:
  <<: *default
  database: {アプリ名}
  username: root # ここを root に変更する
  password: # 特に何も書かなくて大丈夫です。
  socket: /var/lib/mysql/mysql.sock # AmazonLinux2 では MySQL と通信するためのソケットファイルはこれ
~~~

DBの作成

~~~
bundle exec rails db:create RAILS_ENV=production
~~~

マイグレーション

~~~
bundle exec rails db:migrate RAILS_ENV=production
~~~

### 3. master.key を作成する
`master.key` の設定

ローカルの `config/master.key` の一行を全てコピー
↓
clone してきたアプリの `config/master.key` にペースト

(※ `master.key` は ` gitignore` されておりローカルの `master.key` の内容は
GitHubには反映されないため自分でコピペしてくる)

###3. Puma の設定

`config/puma.rb` を編集

~~~config/puma.rb
port        ENV.fetch("PORT") { 3000 } 
~~~

の部分をコメントアウトし、更にその下に

`bind "unix://#{Rails.root}/tmp/sockets/puma.sock"`

を追記

~~~config/puma.rb
# port        ENV.fetch("PORT") { 3000 } 
bind "unix://#{Rails.root}/tmp/sockets/puma.sock"
~~~

###4. Nginxの設定

ディレクトリを移動

~~~
cd  /etc/nginx/conf.d
~~~

/etc/nginx/conf.d下に設定ファイルの作成

~~~
vi {アプリ名}.conf
~~~

以下を記載

~~~/etc/nginx/conf.d/{アプリ名}.conf
# log directory
error_log  /var/www/rails/{アプリ名}/log/nginx.error.log; #自分のアプリケーション名に変更
access_log /var/www/rails/{アプリ名}/log/nginx.access.log; #自分のアプリケーション名に変更
# max body size
client_max_body_size 2G;
upstream app_server {
  # for UNIX domain socket setups
  server unix:/var/www/rails/{アプリ名}/tmp/sockets/puma.sock fail_timeout=0; #自分のアプリケーション名に変更
}
server {
  listen 80;
  server_name ~~~.~~~.~~~.~~~; #自分のElasticIP
  # nginx so increasing this is generally safe...
  keepalive_timeout 5;
  # path for static files
  root /var/www/rails/{アプリ名}/public; #自分のアプリケーション名に変更
  # page cache loading
  try_files $uri/index.html $uri.html $uri @app;
  location @app {
    # HTTP headers
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://app_server;
  }
  # Rails error pages
  error_page 500 502 503 504 /500.html;
  location = /500.html {
    root /var/www/rails/{アプリ名}/public; #自分のアプリケーション名に変更
  }
}
~~~

##第四章 世界に公開

###1.静的ファイルのコンパイル

~~~
bundle exec rails assets:precompile RAILS_ENV=production 
~~~

###2.Nginxを起動

~~~
sudo service nginx start
~~~

###3.Pumaを起動

~~~
bundle exec rails s -e production
~~~


###4.お疲れ様です

これでブラウザに自分の ElasticIP を打ち込むと世界中のパソコンやスマホから自分のアプリにアクセスできます!

### 5.その他

#### 起動や停止
`bundle exec rails s -e production` をバックグラウンドで実行したい時は以下のコマンドで実行。

(これでウィンドウを閉じても大丈夫)

~~~
nohup rails s -e production &
~~~

アプリを終了させたい時は

~~~
ps ax | grep puma
~~~

で puma のプロセスを調べて

~~~
kill -9 {プロセスのPID}
~~~

で停止。

#### 遭遇しそうなエラー

Rails コマンドを実行していると、以下のような Yarn のメッセージが出ることがあります。

~~~
========================================
  Your Yarn packages are out of date!
  Please run `yarn install --check-files` to update.
========================================
~~~

エラー文に従い下記コマンドを実行しましょう

~~~
yarn install --check-files
~~~

## 終わりに

今回はできるだけシンプルな構成になるように心がけました。
世の中で運用されているサービスはもっとより複雑な構成ですが、インフラを学ぶ第一歩としてはこんな感じでOKです!