【Rails】Nginx, Puma な環境によるデプロイ&サーバーの勉強【AWS EC2】

#はじめに
個人開発アプリを
WEBサーバー：Nginx
アプリケーションサーバー：Puma
を利用し、AWS EC2にデプロイしました。

Ruby 2.5.3
Rails 5.2.4.2
MacOS:Catalina 10.15.6 

AWSの設定は既出の優れた記事通りで理解を進めながらOKだったのですが、駆け出したばかりである為、特にNginxの設定(nginx.conf等)が難しく感じ、幾つものエラーを乗り越え、試行錯誤してクリアしました。

最近はPumaをアプリケーションサーバーに選ぶ方が多いかと思います。

デプロイで必要になるnginx.conf,yourapp.confの設定2つを載せている記事がなかった為、誰かのためになるかと思い作成しました。

エラーに躓き、調べることでサーバーへの理解が深まったのでよしとしますが、恐らくチャレンジする皆さまも同じところで躓きそうなので、**自分の場合はこのような設定でデプロイ出来ましたよ**、という体で記事にしたいと思います。

#1 NginxとPumaについて整理
自分自身、復習の意味を込めて両者について整理します（相違点があれば是非ご教示願います！）。

【**Nginx**】...WEBサーバー。ブラウザからのコンテンツリクエストを受け取り、ブラウザにレスポンスする。静的コンテンツ(画像など)のリクエストの場合、WEBサーバーが処理する。動的コンテンツはアプリケーションサーバーが担当する。WEBサーバーの代表はApache,Nginxなど

【**Puma**】...アプリケーションサーバー。NginxがWEBサーバーで静的コンテンツ処理に対し、こちらはNginxでは処理できない動的コンテンツを捌く。WEBサーバーからリクエスト→アプリケーションサーバー受け→Railsアプリケーションの処理結果を、WEBサーバーに返す。代表例としてUnicorn,Pumaなど。現在RailsはPumaをデフォルトのアプリケーションサーバーとして採用している。

PumaとUnicornの選択ですが前者はマルチスレッド、後者はマルチプロセスの違いがあるようです。Pumaの方がより多くのリクエストを効率的に捌ける利点があるようですが、通常使用ではさほど変わりはないという意見もあります。私はRailsで推奨されているPumaを選択しました。

#2 puma.rbの設定
次にpuma.rbの設定です。以下が私の設定です。

```ruby:puma.rb(local)
# アプリケーションディレクトリ
app_dir = File.expand_path("../../", __FILE__)
# ソケット通信を図る為bindでURI指定
bind "unix://#{app_dir}/tmp/sockets/puma.sock"
# PIDファイル所在(プロセスID)
pidfile "#{app_dir}/tmp/pids/puma.pid"
# stateファイルはpumactlコマンドでサーバーを操作する。その所在。
state_path "#{app_dir}/tmp/pids/puma.state"
# 標準出力/標準エラーを出力するファイルの所在。
stdout_redirect "#{app_dir}/log/puma.stdout.log", "#{app_dir}/log/puma.stderr.log", true
threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
threads threads_count, threads_count
#port       ENV.fetch("PORT") { 3000 }
environment ENV.fetch("RAILS_ENV") { "development" }
plugin :tmp_restart

```
portは使用しない為、コメントアウトしました。

PumaとNginxはソケット通信させる為、2行目のbindで指定します。
bindでは下記のようにURIでパスを指定します。

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

#3 nginx.confの設定

Nginxは主に2つのファイルを変更します。
1 nginx.conf...Nginx自体の設定ファイル
2 yourapp.conf...アプリケーション毎のNginx設定ファイル

下記が私のnginx.conf設定です

```ruby:(EC2)etc/nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;

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 2048;

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

    include /etc/nginx/conf.d/*.conf;

    index   index.html index.htm;

    upstream puma {
        server unix:///var/www/rails/yourapp/shared/tmp/sockets/puma.sock;
    }
    server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  Elastic IP(URL);
        root         /var/www/rails/yourapp/current/public;

        location / {
            try_files $uri $uri/index.html $uri.html @webapp;
        }

        location @webapp {
            proxy_read_timeout 300;
            proxy_connect_timeout 300;
            proxy_redirect off;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_pass http://puma;
        }

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

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
    }
    server {
    	listen 443 ssl;
    	server_name Elastic IP(URL);
    	location @webapp {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_pass http://puma;
      }
    }
}
```
#4 yourapp.confの設定

yourapp.confとしていますが、yourappにはあなたが作っているアプリケーション名が入ります。

```ruby:(EC2)/etc/nginx/conf.d/yourapp.conf
  # log directory
  error_log  /var/www/rails/yourapp/shared/log/nginx.error.log;
  access_log /var/www/rails/yourapp/shared/nginx.access.log;
  upstream app_server {
    # for UNIX domain socket setups
    server unix:/var/www/rails/yourapp/shared/tmp/sockets/yourapp-puma.sock fail_timeout=0;
  }
  server {
    listen 80;
    server_name ;
    # nginx so increasing this is generally safe...
    # path for static files
    root /var/www/rails/yourapp/current/public;
    # page cache loading
    try_files $uri/index.html $uri @app_server;
    location / {
      # HTTP headers
      proxy_pass http://app_server;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_redirect off;
    }
    # Rails error pages
    error_page 500 502 503 504 /500.html;
    location = /500.html {
      root /var/www/rails/yourapp/current/public;
    }
    client_max_body_size 4G;
    keepalive_timeout 5;
  }
```


私がデプロイする際に参考にした記事を載せます。

[Rails5+Puma+Nginxな環境をCapistrano3でEC2にデプロイする(後編)](https://qiita.com/himatani/items/3d4293b964255b774769 )

[Rails5アプリケーションのAWSによるネットワーク構築 Nginx+Puma+Capistranoな環境とAWS構築(VPC EC2 RDS CloudFlont Route53 etc)](https://qiita.com/shizuma/items/0bfa71f70573e587669f)

[インフラ初心者がNginx+PumaのRails5アプリケーションをCapistrano3でデプロイした話](https://qiita.com/nrk_baby/items/ce4780e800696beee332 )

##所感
サーバーの扱いに慣れていなかったため、EC2へのデプロイに当たってAWS等の設定よりも、上記NginxとPumaの設定に苦慮した次第です。最終的にCapistrano、CircleCIを利用してAWS EC2にデプロイすることができました。
CDについては先人たちの記事通りに進めていけば難なくできるかと思います。
エラーが多発している時は参りますが、新機能の実装やエラー解決できた時の嬉しさが勝るのでやめられません！