nginx + Puma + Rails 6 + MySQL 8の本番環境をCentOS 8に構築する手順

Ruby

こんにちは。Enjoy IT Life管理人の仁科(@nishina555)です。

Railsアプリケーションを開発する際、開発環境であればrails sを実行するだけで簡単にアプリケーションを立ち上げられます。
しかし、実際にサービスをリリースする際は本番環境の構築が必要です。

今回はRailsアプリケーションの本番環境の構築手順について紹介します。
検証サーバーはConoHa VPS、OSはCentOS8を利用します。

今回作成する本番環境の詳細について

各種バージョンは下記の通りです。

$ cat /etc/redhat-release
CentOS Linux release 8.1.1911 (Core)

$ node -v
v12.18.0

$ ruby -v
ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-linux]

$ rails -v
Rails 6.0.3.1

$ mysqld --version
/usr/libexec/mysqld  Ver 8.0.17 for Linux on x86_64 (Source distribution)

$ mysql --version
mysql  Ver 8.0.17 for Linux on x86_64 (Source distribution)

$ nginx -v
nginx version: nginx/1.14.1
本番環境の補足情報
  • VPSのCentOSイメージ上に、『Rails6 + MySQL8』のアプリケーションを配置する
  • Pumaを利用してnginx(Webサーバー)を連携させる
  • 作業ユーザーは事前に作成した『webuser』というroot権限を持つユーザー
  • ソースコードは『rails new』ではなく『git』を利用し、『/srv』ディレクトリ配下に配置
  • アプリケーション名は『rails-app』

Railsアプリケーションの環境構築

まずはCentOS上にRailsアプリケーションが起動する環境を構築します。

この項目で紹介する『Rails6 + MySQL8』の開発環境の構築手順については『Rails6 + MySQL8の開発環境をCentOS8に構築する手順』で紹介していますので、コマンドの意味の詳細などについてはそちらの記事を参考にしてください。

Rails6 + MySQL8の開発環境をCentOS8に構築する手順

Rubyのインストール

rubyのバージョン管理ができるrbenvを利用してRubyのインストールを行います。1 2 3 4

### rbenvのインストール
$ git clone https://github.com/rbenv/rbenv.git ~/.rbenv
$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
$ ~/.rbenv/bin/rbenv init
→ 手順が出力されるのでそれに従う

### 推奨ライブラリのインストール
$ sudo yum install -y gcc.x86_64 bzip2 openssl-devel libffi-devel readline-devel zlib-devel gdbm-devel ncurses-devel make

### 推奨ライブラリlibyaml-develはPowerTools経由でインストール
$ sudo dnf --enablerepo=PowerTools install -y libyaml-devel

### ruby-buildのインストール
$ mkdir -p "$(rbenv root)"/plugins
$ git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build

### セットアップが正しく完了したかチェックする
$ curl -fsSL https://github.com/rbenv/rbenv-installer/raw/master/bin/rbenv-doctor | bash

Checking for `rbenv' in PATH: /home/webuser/.rbenv/bin/rbenv
Checking for rbenv shims in PATH: OK
Checking `rbenv install' support: /home/webuser/.rbenv/plugins/ruby-build/bin/rbenv-install (ruby-build 20200520-2-gf00582b)
Counting installed Ruby versions: none
  There aren't any Ruby versions installed under `/home/webuser/.rbenv/versions'.
  You can install Ruby versions like so: rbenv install 2.2.4
Checking RubyGems settings: OK
Auditing installed plugins: OK

### rubyのインストール
$ rbenv install -v 2.7.1
$ rbenv global 2.7.1
$ rbenv versions
→ バージョンが表示されればOK

* 2.7.1 (set by /home/webuser/.rbenv/version)

Node.jsのインストール

Rails6ではデフォルトでWebpacekrを利用します。Webpackerを利用するにはNode.jsが必要なのでインストールをします。

nodeはnodenvを利用してインストールします。手順はrubyをrbenvを利用してインストールしたときのそれとほとんど同じです。5 6 7

### nodenvのインストール
$ git clone https://github.com/nodenv/nodenv.git ~/.nodenv
$ echo 'export PATH="$HOME/.nodenv/bin:$PATH"' >> ~/.bash_profile
$ ~/.nodenv/bin/nodenv init
→ 手順が出力されるのでそれに従う

### 推奨ライブラリのインストール
$ sudo yum install -y python36.x86_64 gcc-c++ make

### node-buildのインストール
$ mkdir -p "$(nodenv root)"/plugins
$ git clone https://github.com/nodenv/node-build.git "$(nodenv root)"/plugins/node-build

### セットアップが正しく完了したかチェックする
$ curl -fsSL https://github.com/nodenv/nodenv-installer/raw/master/bin/nodenv-doctor | bash

Checking for `nodenv' in PATH: /home/webuser/.nodenv/bin/nodenv
Checking for nodenv shims in PATH: OK
Checking `nodenv install' support: /home/webuser/.nodenv/plugins/node-build/bin/nodenv-install (node-build 4.9.0)
Counting installed Node versions: none
  There aren't any Node versions installed under `/home/webuser/.nodenv/versions'.
  You can install Node versions like so: nodenv install 2.2.4
Auditing installed plugins: OK

### nodeのインストール
$ nodenv install -v 12.18.0
$ nodenv global 12.18.0
$ nodenv versions
→ バージョンが表示されればOK

* 12.18.0 (set by /home/webuser/.nodenv/version)

Yarnのインストール

Webpacekrで必要になるYarnのインストールを行います。8

$ curl --silent --location https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo
$ sudo yum install -y yarn
$ yarn -v

1.22.4

MySQLの準備

MySQLのインストールを行います。

### mysql2 gemをインストールするのに必要なのでインストールしておく
$ sudo yum install -y mysql-devel

### MySQLのインストール
$ sudo yum install -y mysql-server

$ mysqld --version
→ バージョンが表示されればOK
/usr/libexec/mysqld  Ver 8.0.17 for Linux on x86_64 (Source distribution)

インストールが完了したらMySQLを起動します。

### 起動
$ sudo systemctl start mysqld.service

### ステータス確認
$ sudo systemctl status mysqld

Active: active (running)

### 常時起動にする
$ sudo systemctl enable mysqld.service

Created symlink /etc/systemd/system/multi-user.target.wants/mysqld.service → /usr/lib/systemd/system/mysqld.service.

Railsアプリケーションの配置

Railsアプリケーションの配置と起動の準備を行います。

### gitのインストール
$ sudo yum install -y git

### アプリケーションディレクトリの作成
$ cd /srv
$ sudo mkdir rails-app
$ sudo chown webuser:webuser rails-app

### rails-appディレクトリでgit clone
$ cd rails-app
$ git clone git@github.com:xxxx/rails-app.git .

### gemのインストール
$ bundle install

### Webpackerのインストール
$ bin/rails webpacker:install

データベース接続ユーザーの作成と権限付与を行います。
今回はwebuserというユーザーがwebpassというパスワードでデータベースに接続できるようにします。

$ mysql -u root -p

### ユーザー作成
mysql> create user webuser@'localhost' identified by 'webpass';

### webuserに権限付与
mysql> grant all on *.* to webuser@'localhost';

Webサーバー(nginx)の準備

多くのリクエストをさばけるようにするため、WebサーバーとRailsアプリケーションを連携させます。
今回はPumaを利用した連携方法について紹介します。Webサーバーはnginxを利用しています。

この項目で紹介するWebサーバーとRailsアプリケーションの連携手順は『nginxとPumaを連携し、nginx + Puma + Rails6の開発環境を構築する手順』で紹介していますので、コマンドの意味の詳細などについてはそちらの記事を参考にしてください。

nginxとPumaを連携し、nginx + Puma + Rails6の開発環境を構築する手順

nginxの準備

nginxのインストールと起動を行います。

### インストール
$ sudo yum install -y nginx

### nginxの起動
$ sudo systemctl start nginx

### 自動起動設定
$ sudo systemctl enable nginx

Pumaの設定ファイルの編集

PumaとWebサーバーが連携できるようにPumaの設定を編集します。

Pumaではデフォルトの設定ファイルであるconfig/puma.rbのほか、実行環境に応じたconfig/puma/[実行環境].rbという設定ファイルを用意できます。

RailsアプリにおけるPumaの起動・停止方法まとめ

本番環境用のPumaの設定はconfig/puma/production.rbに記述するとよいでしょう。

$ vim /srv/rails-app/config/puma/production.rb

config/puma/production.rb

# 以下の部分をコメントアウト
# port  ENV.fetch("PORT") { 3000 }

# socketの設定
bind "unix://#{Rails.root}/tmp/sockets/puma.sock"

# デーモン化(バックグラウンドでRailsを起動)
daemonize

nginxの設定ファイルの編集

Pumaと連携できるようにnginxの設定ファイルを編集します。

$ sudo vim /etc/nginx/conf.d/rails-app.conf

rails-app.conf

upstream rails-app {
    # UNIXドメインソケット通信の設定
    server unix:///srv/rails-app/tmp/sockets/puma.sock fail_timeout=0;
}

server {
    # 80番ポート(HTTP)を許可
    listen 80;

    # ホスト名
    server_name xxxxxx;

    # 静的ファイル(画像など)のパスをドキュメントルートに設定
    root /srv/rails-app/public;

    location / {
      # ドキュメントルート配下を以下の順で検索
      # URIのパスに対するファイル(静的コンテンツ)が存在すれば、そのファイル返す。
      # 存在しなければ、動的コンテンツとして@rails-appに内部リダイレクト。
      try_files $uri @rails-app;
    }

    # nginxのリバースプロキシ設定
    # 上記の@rails-appが呼び出された場合のみ以下の設定が読み込まれる
    location @rails-app {
        # サーバの指示通りにリダイレクト
        proxy_redirect off;

        # proxy_set_headerを利用することでサーバーに情報を転送できる
        proxy_set_header Host $http_host; # ホスト名
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 送信元の経路情報
        proxy_set_header X-Real-IP $remote_addr; #送信元のIPアドレス

        # upstreamの名前を記述
        proxy_pass http://rails-app;
    }
}

秘匿情報(credentials)の設定

本番環境でRailsアプリケーションを起動させるにはsecret_key_baseを秘匿情報に登録する必要があります。

secret_key_baseとは、署名入りCookieをはじめとした暗号化された情報の検証を行う際に利用される秘密鍵です。
secret_key_baseを利用することで情報の改ざんを防ぐことができます。

秘匿情報の管理方法はRailsのバージョンによって異なります。
Rails5.2からはsecrets.ymlが廃止され、秘匿情報は暗号化されたファイルcredentials.yml.encと、それを復号するmaster.keyのペアで管理するようになりました。

rails newを実行するとcredentials.yml.encmaster.keyのペアが作成されます。

しかしmaster.key.gitignoreされているため『git pull』でソースコードを配置する』という、本番環境でよく利用されるオペレーションではマスターキーを配置できません。

秘匿情報を本番環境で扱えるようにする方法は3つあります。

秘匿情報を本番環境で扱えるようにする方法
  • master.keyを開発環境からコピーしてくる方法
  • 環境変数にマスターキーをセットする方法
  • 本番環境用のcredentialsファイルとマスターキーのペアを作成する方法

今回は『本番環境用のcredentialsファイルとマスターキーのペアを作成する方法』を利用して秘匿情報を本番環境で管理します。

Rails6ではmulti environment credentials機能が追加され、環境ごとにcredentialsファイルとキーのペアを用意できるようになっています。9

本番環境用のcredentialsファイルとキーのペアであるproduction.yml.encproduction.keyを作成し、secret_key_baseproduction.yml.encに登録します。

デフォルトで用意されているcredentials.yml.encにはsecret_key_baseがあらかじめ登録されていますが、環境別のcredentialsファイルにはsecret_key_baseが登録されていません。

ですので、rails secretを実行してsecret_key_base用の擬似乱数を事前に用意しておくとよいです。

### セッションシークレット用に擬似乱数の生成。シークレットキーを簡単に生成するコマンド
$ bin/rails secret
→ 出力される乱数をコピー

### config/credentials.yml.encの編集
$ EDITOR="vim" bin/rails credentials:edit --environment production
or
$ export EDITOR="vim"
$ bin/rails credentials:edit

→ このタイミングでconfig/credentials/production.keyとconfig/credentials/production.yml.encが作成される

config/credentials/production.yml.enc

secret_key_base: "コピーした乱数をペースト"

credentialsファイルに保存した値はRails.application.credentials.xxxで確認できます。

$ bin/rails c -e production

> Rails.application.credentials.secret_key_base
→ credentialsファイルに登録したsecret_key_baseのvalueが出力されればOK

なお、今回紹介を省略しましたが『環境変数にマスターキーをセットする方法』の場合、master.keyであればRAILS_MEASTER_KEYproduction.keyであればRAILS_PRODUCTION_KEYという環境変数名で登録すればOKです。

エラー対応: No $EDITOR to open file in. Assign one like this

credentialsファイルを開く際にbin/rails credentials:editと実行するとNo $EDITOR to open file in. Assign one like this:というエラーが発生します。

これは、環境変数『EDITOR』がセットされていないのが原因です。
ですので、credentialsファイルを開く際はエディターの指定も必ず行うようにしてください。

シェルの設定ファイルでEDITORをセットすれば、以下のようにbin/rails credentials:editでファイルが開けます。

### .bash_profileに環境変数 EDITOR を設定する
$ echo 'export EDITOR="vim"' >> ~/.bash_profile
$ source ~/.bash_profile

### EDITORをコマンドで指定しなくても編集できるようになる
$ bin/rails credentials:edit

環境変数の設定

環境変数の管理方法は2つあります。

環境変数の管理方法
  • シェルの設定ファイルに記述する方法
  • dotenv-railsというgemを利用する方法

今回は『シェルの設定ファイルに記述する方法』で環境変数を管理します。

例としてconfig/database.ymlに記載されている、本番環境用のパスワードENV['RAILS_APP_DATABASE_PASSWORD']の値をセットします。

今回の環境ではbashを利用しているため.bash_profileに環境変数を保存します。
設定ファイルをリロード後、rails consoleで環境変数の値が確認できればOKです。

$ echo 'export RAILS_APP_DATABASE_PASSWORD="xxx"' >> ~/.bash_profile
$ source ~/.bash_profile

$ bin/rails c -e production
> ENV['RAILS_APP_DATABASE_PASSWORD']
→ 設定したパスワードが表示されればOK

アセットのコンパイル

本番環境ではアセットを事前にコンパイルしておく必要があります。

Rails6からはWebpackerが標準でGemfileに追加されるようになり、JavaScriptのコンパイルはWebpackerが、CSSおよび画像ファイルのコンパイルはSprockets4が行っています。

アセットのコンパイルは以下のコマンドで実施します。

$ bin/rails assets:precompile

$ ls public/assets/
→ ファイルがあればOK

$ ls public/packs/
→ ファイルがあればOK

コマンドを実行することで、app/assets配下とapp/packs配下のアセットファイルがコンパイルされてpublic/配下に配置されます。
public/配下にassetspacksディレクトリが配置され、ファイルが生成されていることが確認できればOKです。

データベースの用意

本番環境用のデータベースの作成とマイグレーションを実行します。

$ bin/rails db:create RAILS_ENV=production
$ bin/rails db:migrate RAILS_ENV=production

本番環境での起動確認

本番環境でRailsアプリケーションを起動する準備が整ったので、確認を行っていきます。

### nginxを再起動
$ sudo systemctl restart nginx

### Railsを起動
$ bin/rails s -e production
→ Pumaでデーモン化の設定を行っている場合、バックグラウンドでRailsが起動します。

http://[パブリックIP]/*で画面が表示できればOKです。

たとえば、Eventというモデルをscaffoldで作成したサンプルアプリケーションの場合、http://[パブリックIP]/eventsで以下のような画面が表示されます。

もし画面にアクセスできない場合、サーバーのファイアウォールの設定が悪さをしている可能性があります。
Webサーバーがlistenしている80番ポートで接続できるようにするため、必要に応じてファイアウォールの設定を変更しておきましょう。

### 80番ポートの開放
$ sudo firewall-cmd --add-port=80/tcp --zone=public --permanent

### 設定を反映
$ sudo firewall-cmd --reload

### 設定確認
$ sudo firewall-cmd --list-all

まとめ

以上でnginx + Puma + Rails6 + MySQLの本番環境をCentOS8に構築する手順の紹介を終わります。

Railsアプリケーションの本番環境構築でやること
  • Railsアプリケーションの環境構築
  • Webサーバー(nginx)の準備
  • 秘匿情報(credentials)の設定
  • 環境変数の設定
  • アセットのコンパイル
  • データベースの用意

なお、今回検証サーバーを用意するために利用したConoHa VPSは、1ヶ月に満たない利用の場合は時間単位で料金が請求されるので、数十円くらいでサーバーの勉強や検証環境が用意できるオススメのVPSです!

この記事がいいなと思いましたらツイッター(@nishina555)のフォローもよろしくお願いします!

Rubyのオススメ参考書