ConoHa VPS(CentOS 8.2)に Rails 6 + PostgreSQL + Nginx + Unicorn + Capistrano でデプロイする

ConoHa VPS(CentOS 8.2)に Rails 6 + PostgreSQL + Nginx + Unicorn + Capistrano でデプロイする

September 3, 2020

前置き #

初デプロイ時に相当苦労し、調べに調べてなんとかデプロイ完了まで漕ぎ着けました(デプロイするのに数日間…)。作業中は手順を逐一記録しており、それらをデプロイ完了後に改めて整理したのが本記事の手順です。本手順を作成した後で一度 VPS を削除し、改めてゼロから本手順に通りに作業したところ、無事にデプロイができました。そのため、ある程度信頼できる手順になっているのではないかと思います。なおローカル環境については Mac でターミナルを使用して作業を進めています。

また、パッケージのインストール部分について補足しておきます。

パッケージ(PostgreSQL など)をインストールする部分では、CentOS (今回は 8.2)の標準リポジトリからインストールできるバージョンを利用しています。つまり、パッケージのバージョンは特に指定せず、その時に CentOS が標準でインストールするものを導入する形です。ただしこの場合、必ずしも最新版のパッケージがインストールされるわけではありません。例えば、本記事作成時点の PostgreSQL 最新版は 12 ですが、CentOS 8.2 の標準だと 10 がインストールされます。

パッケージ開発元のリポジトリから最新版を指定してインストールすることもできるのですが、その場合はバージョンを明示する必要があったりと、今後さらにバージョンが変わっていった時に、手順の内容が使えない(古い)ものになったために不用意なエラーが起こる可能性があります。今回は手順の汎用性を考慮して全て CentOS 標準のバージョンをインストールしています。

CentOS 標準のバージョンで困ることは無いと考えていますが、もしも最新版を使いたい場合は、一度本手順に沿ってデプロイまで済ませた後、個別にバージョンを変更するのが安定しているかと思います。

いずれにせよ、初学者にとってはデプロイするというハードルを超えるのが一苦労なので、そこまでたどり着くことが本手順の第一目的です。

以上、前置きでした。それでは以下が手順です。

1.ConoHa の VPS を契約する #

メモリ等のプランは任意。私は以下を選択。

  • リージョン:東京、メモリ:1 GB、CPU:2 Core、SSD:100GB、880 円/月
  • イメージタイプ:CentOS 8.2(64bit)
  • root パスワード:任意のパスワード
  • ネームタグ:任意のネーム
  • 追加オプション:全てデフォルトのまま(例:SSH Key 使用しない)

以降、VPS のことをサーバと記載。

2.サーバにログインする #

1で作成したサーバの詳細ページを開き、IP アドレスを確認。その後、ターミナルから以下のコマンドでサーバに接続。

ssh root@IPアドレス

その後、

The authenticity of host IPアドレス can't be established.
ECDSA key fingerprint is SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.
Are you sure you want to continue connecting (yes/no/[fingerprint])?

上記のように、known hosts に追加するかと聞かれるので、yes と入力し回答。

これでローカルの ~/.ssh/known_hosts にある known hosts ファイルに追記される。

その後パスワードを求められるので、1で設定した root パスワードを入力してログイン。

3.作業用ユーザを作成する #

今後のために、ここで作業用ユーザを作成。

以下コマンドで新規ユーザ作成。

adduser ユーザ名

ここで作成したユーザのことを、以降は作業用ユーザと記載する。

その後、パスワードを設定。

passwd 作業用ユーザ名

root 権限(sudo 権限)を付与するために、設定ファイルを開く。

visudo

以下の部分を探す。

## Allow root to run any commands anywhere
root    ALL=(ALL)   ALL

キーボードの i を押下して挿入モードに移行し、上記を下記の通り更新。

## Allow root to run any commands anywhere
root          ALL=(ALL)       ALL
作業用ユーザ名   ALL=(ALL)       ALL

ESC キーを押下してコマンドモードに戻り、その後、:wq を入力しエンターで、ファイルを保存。

sudo 実行時に、パスワード入力を求められないように設定を変えるため、再び設定ファイルを開く。

visudo

以下の部分を探す。

## Same thing without a password
# %wheel        ALL=(ALL)       NOPASSWD: ALL

先ほどと同様に操作し、上記を下記の通り更新して保存。

## Same thing without a password
# %wheel       ALL=(ALL)       NOPASSWD: ALL
%作業用ユーザ名   ALL=(ALL)       NOPASSWD: ALL

ここまでの設定ができているかを確認する。作成したユーザにスイッチしてから、sudo コマンドを使用してみる。

su 作成したユーザ名
sudo echo test

上記実行後、パスワード入力を求められずに、test とだけ表示されれば OK.

ここまで完了したら、exit で一度サーバから抜けて、作成したユーザでログインできることを確認する。

exit
exit
ssh 作成したユーザ名@IPアドレス

ユーザ作成後に設定したパスワードを入力し、ログインする。

その後、root によるログインを不許可にしておくため、下記で設定ファイルを開く。

sudo vi /etc/ssh/sshd_config

下記の記載を探す。

# Authentication:

#LoginGraceTime 2m
PermitRootLogin yes
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10

上記のうち、PermitRootLogin の部分を no に変えて、下記の通りとして保存する。

# Authentication:

#LoginGraceTime 2m
PermitRootLogin no
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10

設定を反映させるために sshd のデーモンを再起動し、設定を読み込ませる。以下のコマンドを実行。

sudo systemctl restart sshd

一度サーバから抜けて、root でログインを試してみると、正しいパスワードを入力しても、Permission denied となってログインできなくなっている。

4.Git をインストールする #

3で作業用ユーザをせっかく作成したわけだが、一回一回 sudo するのが手間のため、以降は root ユーザで作業をしていく。

作業用ユーザでサーバにログイン後、root ユーザへスイッチ。

su root

その後、サーバで下記を実行し、Git をインストール。

*メモ:CentOS 8 では、パッケージ管理システムとして Yum ではなく DNF が使われている(DNF は Yum の事実上の後継)。現状、引き続き yum コマンドを使用することもできるが、yum コマンドを入力しても内部的には dnf が呼び出されており、将来的に yum は廃止されるため、以降使用するのは dnf コマンドに統一しておく。(といっても、yum と打つところを dnf と打つだけの違い。)

dnf -y install git

ちゃんとインストールできたか確認する。下記のコマンドを実行。

git --version

git version 2.18.4 などとバージョンが表示されれば OK.

5.rbenv をインストールする #

下記を実行。リモートの rbenv リポジトリを/usr/local/rbenv というディレクトリにクローンしている。

git clone https://github.com/rbenv/rbenv.git /usr/local/rbenv

次にパスを通す(環境変数を設定する)ため、ファイルを作成する。

vi /etc/profile.d/rbenv.sh

ファイルが作られ、開かれるので下記を記述する。

export RBENV_ROOT=/usr/local/rbenv
export PATH="$RBENV_ROOT/bin:$PATH"
eval "$(rbenv init -)"

そして、設定ファイルを読み込ませるために以下を実行。

source /etc/profile.d/rbenv.sh

その後、ちゃんとインストールできたか確認する。

rbenv --version

rbenv 1.1.2 などとバージョンが表示されれば OK.

6.ruby-build をインストールする #

root ユーザで下記を実行。ruby-build は、rbenv でインストールを実行するときに必要なプラグイン。

git clone https://github.com/rbenv/ruby-build.git /usr/local/rbenv/plugins/ruby-build

7.開発パッケージをインストールする #

Ruby をインストールするために必要なパッケージをインストールする。

dnf -y groupinstall "Development Tools"
dnf -y install gcc gcc-c++ glibc-headers openssl-devel readline readline-devel zlib zlib-devel libffi-devel libxml2 libxml2-devel libxslt libxslt-devel mysql-devel bzip2

2つ目のコマンドの中で、1つ目のコマンドでインストールしたものと重複するものが含まれている場合があるが、その場合は未インストールのものだけを自動的にインストールしてくれるので、そこまで気にしなくても大丈夫。

8.Ruby をインストールする #

以下を入力して、rbenv でインストールできる Ruby のバージョン一覧を表示する。

rbenv install -list

表示される結果例は下記の通り。

2.5.8
2.6.6
2.7.1
jruby-9.2.13.0
maglev-1.0.0
mruby-2.1.2
rbx-5.0
truffleruby-20.2.0
truffleruby+graalvm-20.2.0

Ruby をインストールする。バージョンはローカルで使っているものを指定。私の場合は 2.7.1 をインストールする。下記を実行。

rbenv install 2.7.1

インストールにはそれなりに時間がかかるので、気長に。

ちゃんとインストールされたかを確認する。

rbenv versions

2.7.1 などと表示されれば OK.

次にサーバで利用する Ruby の使用バージョンを設定する。

rbenv global 2.7.1
rbenv rehash

設定できているか確認する。

ruby -v

2.7.1 と表示されていれば OK.

次に、作業用ユーザでも同様のことを行う。作業用ユーザに戻す。

exit

さらに以下を入力し、ディレクトリを移動。

cd /usr/local/rbenv/

事前確認のため、以下を実行。

ls -la

ファイルやフォルダの所有者が全て root になっていることを確認。続いて、以下を実行。

sudo chown 作業用ユーザ名 version
sudo chown 作業用ユーザ名 shims

その後、再度以下を実行。

ls -la

version と shims の所有ユーザが作業用ユーザ名に変更されていることを確認する。

一度サーバからログアウトし、改めて作業用ユーザでログインする。その後、さらに以下を実行。

rbenv global 2.7.1
rbenv rehash

最後に、以下を入力し、設定を確認。

ruby -v

2.7.1 と表示されていれば OK.

9.Bundler をインストールする #

root ユーザにスイッチする。

su root

そして以下のコマンドを実行。

rbenv exec gem install bundler
rbenv rehash

インストールできているか確認する。

which bundler

上記入力後、/usr/local/rbenv/shims/bundler と返ってくれば OK.

10.Node.js をインストールする #

以降、引き続き root ユーザのまま。インストールを実行。

dnf install -y nodejs

インストールできていることを確認する。

node -v

v10.21.0 などとバージョンが表示されれば OK.

11.Yarn をインストールする #

以下を実行。

npm install -g yarn

インストールできていることを確認する。

yarn -v

1.22.5 などとバージョンが表示されれば OK.

12.PostgreSQL をインストールする #

以下を実行。

dnf install -y postgresql postgresql-server postgresql-devel postgresql-contrib postgresql-docs
postgresql-setup initdb

OS 起動時に PostgreSQL も自動起動するように設定。

systemctl enable postgresql

自動起動設定できたことを確認。

systemctl is-enabled postgresql

enabled であれば OK.

現時点では PostgreSQL は起動していないため、起動させる。

systemctl start postgresql

インストールできたことを確認。

psql --version

psql (PostgreSQL) 10.6 などと表示されれば OK.

さらに、PostgreSQL が起動していることを確認する。

systemctl status postgresql

active (running)になっていれば OK.

次に PostgreSQL の設定を変える。下記を実行してファイルを開く。

vi /var/lib/pgsql/data/postgresql.conf

CONNECTIONS AND AUTHENTICATION の項目にある以下

#listen_addresses = 'localhost'

のコメントアウトを解除して下記の通り変更する。

listen_addresses = '*'

変更後、さらにもう1つファイルを開く。

vi /var/lib/pgsql/data/pg_hba.conf

ファイル下部にある以下を、

# TYPE  DATABASE        USER            ADDRESS                 METHOD

# "local" is for Unix domain socket connections only
local   all             all                                     peer
# IPv4 local connections:
host    all             all             127.0.0.1/32            ident
# IPv6 local connections:
host    all             all             ::1/128                 ident
# Allow replication connections from localhost, by a user with the
# replication privilege.
local   replication     all                                     peer
host    replication     all             127.0.0.1/32            ident
host    replication     all             ::1/128                 ident

次のように変更する。(途中3行をコメントアウト、最終行に2行の記載追加)

# TYPE  DATABASE        USER            ADDRESS                 METHOD

# "local" is for Unix domain socket connections only
# local   all             all                                     peer
# IPv4 local connections:
# host    all             all             127.0.0.1/32            ident
# IPv6 local connections:
# host    all             all             ::1/128                 ident
# Allow replication connections from localhost, by a user with the
# replication privilege.
local   replication     all                                     peer
host    replication     all             127.0.0.1/32            ident
host    replication     all             ::1/128                 ident
local   all             all                                     trust
host    all             all             0.0.0.0/0               md5

設定を反映させるため、PostgreSQL を再起動する。

systemctl restart postgresql

13.Rails アプリで使用する DB を作成する #

一度ターミナルから目を離し、デプロイしたい Rails アプリの config/database.yml を開いてファイル内の以下の記述を確認する。

production:
  <<: *default
  database: test_production
  username: test
  password: <%= ENV['TEST_DATABASE_PASSWORD'] %>

“test"の部分は rails new した時のプロジェクト名が設定されている。

その後、ターミナルに戻って以下の作業。

PostgreSQL にデフォルトで作られている、postgres というユーザを使って PostgreSQL に接続する。

psql -U postgres

と入力し、プロンプトが postgres=# となったことを確認する。

その後、以下コマンドによりロールを作成したいのだが、

CREATE ROLE "ロール名" WITH SUPERUSER LOGIN;

“ロール名"の部分には、config/database.yml の username に書いてある名称を記述する。今回の例では test なので、

CREATE ROLE "test" WITH SUPERUSER LOGIN;

となる。これを入力して実行する。

次に、以下コマンドによりデータベースを作成したいのだが、

CREATE DATABASE "データベース名"

“データベース名"の部分には、config/database.yml の database に書いてある名称を記述する。今回の例では test_production なので、

CREATE DATABASE "test_production";

となる。これを入力して実行する。

データベースの操作はこれで終わりなので、

\q

と入力して、PostgreSQL から抜ける。

最後に、PostgreSQL を再起動しておく。

systemctl restart postgresql

14.Nginx をインストールする #

以下のコマンドを実行。

dnf -y install nginx

インストールされていることを確認。

nginx -v

nginx version: nginx/1.14.1 などと表示されれば OK.

次に以下を実行して、OS 起動時に Nginx も自動起動するよう設定しておく。

systemctl enable nginx

自動起動設定できたことを確認。

systemctl is-enabled nginx

enabled であれば OK.

次に以下を実行して、Nginx を起動する。

systemctl start nginx

Nginx が起動していることを確認する。

systemctl status nginx

active (running)になっていれば OK.

次に、Nginx に http で接続できるように、firewalld の 80 番ポートを開放する。

firewall-cmd --add-service=http --permanent

firewalld をリロードする。

firewall-cmd --reload

その後、ウェブブラウザを開いてサーバの IP アドレスを入力して接続し、「Welcome to nginx」が出れば OK.

15.Capistrano でデプロイできるようにする #

15 − 1.サーバと GitHub で SSH 接続できるようにする #

Capistrano を使うために、サーバと GitHub 間で SSH 接続できるようにする。

ここで作業用ユーザに戻る。

exit

ホームディレクトリに移動。

cd

その後、以下で公開鍵と秘密鍵を作成。

ssh-keygen -t rsa

この時、

Enter file in which to save the key (/home/devsup/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:

と聞かれるが、全てそのまま Enger を押下すれば OK.

次に、以下を入力し、公開鍵の中身を表示する。

cat ~/.ssh/id_rsa.pub

すると、

ssh-rsa XXXX...= ユーザ名@IPアドレス

といったものが表示されるので、ssh-rsa から最後の IP アドレスまで全てをコピー。

その後、GitHub にログインし、SSH キーの登録ページ(https://github.com/settings/keys)から New SSH Key を押下して、コピーした内容をペーストし登録。

これで、サーバと GitHub 間で SSH 接続できるようになった。

次に、サーバにアプリ公開用のディレクトリを作成する。

まずディレクトリを移動。

cd /var

www ディレクトリを作成。

sudo mkdir www

www ディレクトリの所有ユーザとグループを root から変更する。

sudo chown -R 作業用ユーザ名:作業用ユーザ名 www

所有が変わったことを確認する。

ls -l

root ではなく、作業用ユーザの所有に変わっていれば OK.

15 − 2.Capistrano、Unicorn をインストールする #

ローカルで Rails アプリを開き、Gemfile に以下を追記。

gem 'dotenv-rails'
gem 'unicorn'
gem 'mini_racer', platforms: :ruby

group :development, :test do
  gem 'capistrano'
  gem 'capistrano-bundler'
  gem 'capistrano-rails'
  gem 'capistrano-rbenv'
  gem 'capistrano3-unicorn'
end

Gemfile 更新後、ローカルで bundle install 実行。

bundle install

次に、Capistrano の設定ファイルを作成する。ローカルで実行。

bundle exec cap install

/Capfile が作成されるので、そのファイルに以下を追記。

require 'capistrano/setup'
require 'capistrano/deploy'
require 'capistrano/rbenv'
require 'capistrano/bundler'
require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'
require 'capistrano3/unicorn'

デフォルトで記載されているものもあるため、不足しているものについて、上記となるように追記する。

次に、/config/deploy/production.rb を開き、以下を追記。

server 'サーバのIPアドレス', user: 'サーバの作業用ユーザ名', roles: %w{app db web}
set :ssh_options, keys: 'ローカルの秘密鍵のパス'

ローカルの秘密鍵のパスは、"/Users/ユーザ名/.ssh/id_rsa” といった感じになる。

次に、Gemfile.lock を開き、インストールされた Capistrano のバージョンを確認。

capistrano (3.14.1)
  airbrussh (>= 1.0.0)
  i18n
  rake (>= 10.0.0)
  sshkit (>= 1.9.0)

capistrano の右の 3.14.1 がバージョンを示している。

次に、/config/deploy.rb を開き、既存の記述を全て削除した後、下記を記載。

# config valid only for current version of Capistrano

lock "~> 3.14.1" # Capistranoのバージョン

set :application, 'アプリケーション名' # アプリケーション名
set :repo_url, 'https://github.com/xxxx/yyyy' # クローンするGitHubリポジトリ(xxxxはユーザ名、yyyyはアプリ名)
set :deploy_to, '/var/www/アプリケーション名' # デプロイ先のディレクトリ
set :linked_files, %w{.env config/secrets.yml} # シンボリックリンクを貼るファイル
set :linked_dirs, %w{log tmp/pids tmp/cache tmp/sockets public/uploads} # シンボリックリンクを貼るディレクトリ
set :keep_releases, 3 # 保持するバージョンの数
set :rbenv_ruby, '2.7.1' # Rubyのバージョン
set :rbenv_type, :system
set :log_level, :debug # 出力するログのレベル 概要レベルにしたければ :info とする

namespace :deploy do
  desc 'Restart application'
  task :restart do
    invoke 'unicorn:restart'
  end
  desc 'Create database'
  task :db_create do
    on roles(:db) do |host|
      with rails_env: fetch(:rails_env) do
        within current_path do
          execute :bundle, :exec, :rails, 'db:create'
        end
      end
    end
  end
  desc 'Run seed'
  task :seed do
    on roles(:app) do
      with rails_env: fetch(:rails_env) do
        within current_path do
          execute :bundle, :exec, :rails, 'db:seed'
        end
      end
    end
  end
  after :publishing, :restart
  after :restart, :clear_cache do
    on roles(:web), in: :groups, limit: 3, wait: 10 do
    end
  end
end

アプリケーション名、Capistrano や Ruby のバージョン、GitHub のリポジトリは環境(人)によって異なるので、適宜変更。アプリケーション名は、Rails new した時のプロジェクト名に合わせておけば適当かと。

次に、config 直下に unicorn ディレクトリを作成し、その直下に production.rb を作成する(/config/unicorn/production.rb)。作成した production.rb に以下を記載。

$worker  = 2
$timeout = 30
$app_dir = "/var/www/アプリケーション名/current"
$listen  = File.expand_path 'tmp/sockets/unicorn.sock', $app_dir
$pid     = File.expand_path 'tmp/pids/unicorn.pid', $app_dir
$std_log = File.expand_path 'log/unicorn.log', $app_dir
worker_processes  $worker
working_directory $app_dir
stderr_path $std_log
stdout_path $std_log
timeout $timeout
listen  $listen
pid $pid
preload_app true
before_fork do |server, worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!
  old_pid = "#{server.config[:pid]}.oldbin"
  if old_pid != server.pid
    begin
      Process.kill "QUIT", File.read(old_pid).to_i
    rescue Errno::ENOENT, Errno::ESRCH
    end
  end
end
after_fork do |server, worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
end

アプリケーション名の部分は、/config/deploy.rb 内で記述したアプリケーション名を記載する。

ここまで終わったら、更新内容をコミットして、GitHub にプッシュする。

15 − 3.Unicorn の自動起動設定をする #

サーバに戻り、以下を実行。

sudo vi /usr/lib/systemd/system/unicorn_アプリケーション名.service

作成されたファイルに以下を記載。

[Unit]
Description=unicorn アプリケーション名 service
After=network.target

[Service]
User=作業用ユーザ名
Environment=RAILS_ENV=production
WorkingDirectory=/var/www/アプリケーション名/current
PIDFile=/var/www/アプリケーション名/current/tmp/pids/unicorn.pid
ExecStart=/usr/local/rbenv/shims/bundle exec unicorn -c /var/www/アプリケーション名/current/config/unicorn/production.rb -D
Restart=always

[Install]
WantedBy=multi-user.target

記述の書式が正しいことをチェック。

sudo systemd-analyze verify /usr/lib/systemd/system/unicorn_アプリケーション名.service

何も表示されなければ問題ないということなので OK.

OS 起動時に Unicorn も自動起動するように設定。

sudo systemctl enable unicorn_アプリケーション名.service

自動起動設定できているか確認。

sudo systemctl is-enabled unicorn_アプリケーション名.service

enabled であれば OK.

なお Unicorn はこの後デプロイする中で起動されるので、今は起動しない。

15 − 4.Nginx の設定ファイルを作成 #

以下を実行。

sudo vi /etc/nginx/conf.d/アプリケーション名.conf

作成されたファイルに以下を記載。

upstream unicorn_アプリケーション名 {
  server unix:/var/www/アプリケーション名/current/tmp/sockets/unicorn.sock;
}
server {
  listen 80;
  server_name サーバのIPアドレス;
  root /var/www/アプリケーション名/current/public;
  access_log /var/log/nginx/アプリケーション名_access.log;
  error_log /var/log/nginx/アプリケーション名_error.log;
  location / {
    try_files $uri @unicorn;
  }
  location @unicorn {
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass http://unicorn_アプリケーション名;
  }
}

設定ファイル作成後、以下のコマンドで設定ファイルに問題ないかをテストする。

sudo nginx -t

下記のメッセージが表示され、テストに成功していることが確認できれば OK.

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

その後、設定を反映させるために Nginx を再起動する。

sudo systemctl restart nginx

15 − 5.デプロイできる状態か確認する #

ローカル(のアプリのプロジェクトディレクトリ)で以下を実行する。

bundle exec cap production deploy:check

なお、デプロイチェックにあたり、GitHub について、以下の点に留意。

  • ローカルと GitHub で SSH 接続できる(GitHub に鍵が登録されている)状態となっていること。
  • GitHub のリポジトリがパブリックとなっていること。

GitHub のプライベートリポジトリでデプロイしたい場合は、本記事下部の「80 − 2.GitHub のプライベートリポジトリからデプロイする」を参照して設定しておく。

デプロイチェック実行後、

ERROR linked file /var/www/アプリケーション名/shared/.env does not exist on IPアドレス

というエラーが出るが想定内なので大丈夫。

上記処理内ではデプロイできるかのチェックだけでなく、サーバで先ほど作成した www ディレクトリ配下にアプリ用のディレクトリも作っている。

15 − 6.環境変数を設定する #

ローカルで以下を実行し、乱数を生成する。

bundle exec rake secret

出力された乱数をコピーしておく。

次にサーバで、secrets.yml ファイルを作成する。

sudo vi /var/www/アプリケーション名/shared/config/secrets.yml

ファイルが開いたら、下記の通り、ローカルで生成した乱数をペーストして保存する。

production:
  secret_key_base: 生成した乱数

次に、.env ファイルを作成する。

sudo vi /var/www/アプリケーション名/shared/.env

ファイルが開いたら、Rails アプリで.env に記述していた環境変数をコピーして、上記の.env ファイルにペーストする。

15 − 7.改めてデプロイできる状態か確認する #

改めてローカル(のアプリのプロジェクトディレクトリ)で以下を実行する。

bundle exec cap production deploy:check

今度はエラーが発生しないことを確認する。これでデプロイできる状態となった。

16.デプロイを実行する #

ローカルで以下を実行する。

bundle exec cap production deploy

bundler:install のところで時間がかかるため、固まったのか…?という不安と戦いながらじっと耐えるべし。

もし本当に固まったように思われた場合、Ctrl + C でデプロイを中止し、もう一度デプロイコマンドを実行すると、次はうまくいくことが多い。

これでようやくデプロイ完了。アクセスしてみる。

http://IP アドレス(トップページを設定していないのであれば、http://IP アドレス/blogs など存在するページを指定)

Rails アプリのページが表示されることを確認する。

80.その他設定編 #

これまででデプロイはできたわけだが、以降、追加の設定について。

80 − 1.SSH のポート番号を変更する #

セキュリティの観点から実施しておく。

root ユーザで作業する。

su root

まずは、SELinux(Linux カーネルのセキュリティ機能のひとつ)の状態を確認する。

getenforce

CentOS 8.2 では、デフォルトが Disabled となっていることを確認。そのままにしておく。

ファイルを開き、

vi /etc/ssh/sshd_config

以下の部分を見つけ、

# If you want to change the port on a SELinux system, you have to tell
# SELinux about this change.
# semanage port -a -t ssh_port_t -p tcp #PORTNUMBER
#
#Port 22
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::</code></pre>

#Port 22 の部分のコメントアウトを外し、適当な番号を設定する。下記は例。

# If you want to change the port on a SELinux system, you have to tell
# SELinux about this change.
# semanage port -a -t ssh_port_t -p tcp #PORTNUMBER
#
Port 50022
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::

ポート番号は自由に決めることができるが、自分のサーバ内で他のサービスが使っているポート番号と被ると問題になるので注意。とりあえず 49152〜65535 の間で適当に決めるのが良い。

どんなサービスがどんなポート番号を使っているかは、参考までに下記を参照。

TCP や UDP におけるポート番号の一覧 - Wikipedia

また、設定ファイル内に、「# If you want to change the port on a SELinux system, you have to tell …」と記載がある通り、先に確認した SELinux が Disabled ではなく有効になっていると、SELinux の設定も変える必要がある。

次に、Firewalld のデフォルト設定の格納場所である「/usr/lib/firewalld/services/」直下にある「ssh.xml」を、カスタム設定の格納場所である「/etc/firewalld/services/」直下へコピーする。

cp /usr/lib/firewalld/services/ssh.xml /etc/firewalld/services/ssh.xml

コピーして作成したファイルを開いて編集する。

vi /etc/firewalld/services/ssh.xml

以下部分のポート番号を、

<port protocol="tcp" port="22"/>

先ほど設定したポート番号に変える。

<port protocol="tcp" port="50022"/>

設定を反映させるため、Firewalld をリロード、SSHD を再起動する。

firewall-cmd --reload
systemctl restart sshd

ここまで終わったら、ターミナルをもう一つ立ち上げる。この時、上記作業に使ったターミナルはサーバに接続したままにしておき、決して閉じないように。万が一設定がうまくいっていないままターミナルを閉じると、二度と繋げなくなってしまう。

新たに立ち上げたターミナルで以下を実行。

ssh 作業用ユーザ名@IPアドレス

結果、

ssh: connect to host IPアドレス port 22: Operation timed out

になっていれば OK. 22 番ポートは閉じられている。

次に以下で接続。以下は SSH のポート番号を 50022 にしている場合。

ssh 作業用ユーザ名@IPアドレス -p 50022

接続できることを確認。

ここまでの作業で SSH のポート番号が変わったわけだが、それと同時に、Capistrano でデプロイする時にもそのポート番号を使うように設定しておかないといけない。

ローカルで Rails アプリの/config/deploy/production.rb を開き、

server 'サーバのIPアドレス', user: 'サーバの作業用ユーザ名', roles: %w{app db web}
set :ssh_options, keys: 'ローカルの秘密鍵のパス'

上記に、ポート番号の設定を追加する。下記はポート番号が 5022 の場合。

server 'サーバのIPアドレス', user: 'サーバの作業用ユーザ名', port: '50022', roles: %w{app db web}
set :ssh_options, keys: 'ローカルの秘密鍵のパス'

変更後は、コミットして GitHub へプッシュ。

最後にローカルで、

bundle exec cap production deploy:check

を実行して、ちゃんとデプロイできるようになっているか確認しておく。

80 − 2.GitHub のプライベートリポジトリからデプロイする #

GitHub のリポジトリをプライベートにする場合は、デプロイの設定にも手を入れる必要がある。

まず、GitHub の以下ページから、

https://github.com/settings/tokens

Generate new token を押下し、repo 項目の Full control of private repositories をチェックして生成。トークンが表示されたらコピーしておく。

その後、Rails アプリの/config/deploy.rb を開き、

set :repo_url, 'https://github.com/xxxx/yyyy' # クローンするGitHubリポジトリ(xxxxはユーザ名、yyyyはアプリ名)

上記となっている set :repo_url を、以下のように編集。https://github.com/ の部分を、 https://トークン:@github.com/ に変える。

set :repo_url, 'https://トークン:@github.com/xxxx/yyyy' # クローンするGitHubリポジトリ(xxxxはユーザ名、yyyyはアプリ名)

最後にローカルで下記を実行し、

bundle exec cap production deploy:check

デプロイできる状態となっていることを確認しておく。

80 − 3.タイムゾーンを日本時間で統一する #

必要であれば実施。

アプリ内で時刻を使用する場合、OS(CentOS)、DB(PostgreSQL)、Rails の時刻基準を合わせておくと良さそう。

まず、CentOS のタイムゾーンを変更する。サーバ上で、root ユーザにて以下を実行。

timedatectl set-timezone Asia/Tokyo

上記後、以下で確認。

timedatectl status

Time zone: Asia/Tokyo (JST, +0900) となっていれば OK.

次に PostgreSQL のタイムゾーンを変更。DB にアクセスし、

psql -U postgres

プロンプトが、postgres=# となったのを確認して、DB 一覧を確認。

\l

タイムテーブルを変更したい DB の名前をコピーしておき、一度 DB から抜ける。

\q

そしてタイムゾーンを変更したい DB に接続する。

psql -U postgres -d DB名

プロンプトが、DB 名=# となったのを確認して、以下でタイムゾーンを変更。

ALTER DATABASE "DB名" SET timezone TO 'Asia/Tokyo';

その後以下を実行し、

SELECT CURRENT_TIMESTAMP;

日本時間で現在時刻が表示されていれば OK、DB から抜ける。

\q

なお、上記では DB 単位でタイムゾーンを設定しているため、他の DB のタイムゾーンは変わっていないことに注意。

最後に Rails のタイムゾーン設定を変える。

ローカルで Rails アプリの、config/application.rb を開く。

そして、class Application < Rails::Application ブロックの中に以下2行を追記。

module XXXX
  class Application < Rails::Application
    .........
    ......
    ...
    config.time_zone = 'Tokyo' # 追記
    config.active_record.default_timezone = :local # 追記
  end
end

最後に忘れずコミット&プッシュ&デプロイしておくこと。

80 − 4.ログローテーションの設定 #

放っておくと際限なくログファイルが膨れ上がってしまうため、自動的に削除するように設定しておく。

まず、Nginx のログについてはデフォルトでログローテーションされるようになっているため対応不要。

次に、Unicorn のログについて設定。/etc/logrotate.d/の下に設定ファイルを作る。サーバ上で root ユーザにて以下を実行。

vim /etc/logrotate.d/アプリケーション名_unicorn

開いたファイルに以下を記載。

/var/www/アプリケーション名/current/log/*unicorn.log {
  create 0664 作業用ユーザ名 作業用ユーザ名
  daily
  rotate 10
  missingok
  notifempty
  compress
  postrotate
    pid=/var/www/アプリケーション名/current/tmp/pids/unicorn.pid
    test -s $pid && kill -USR1 "$(cat $pid)"
  endscript
}

上記では、1日1ファイルを作成、10 世代保存という設定にしている。

最後に、Rails のログについて設定。ローカルで Rails アプリの config/environments/production.rb を開き、下記を追加する。設定内容の意味はコメントに記載している通り。

# production.0, production.1, production.2 の3世代保持 10Mを超えるとローテーション
config.logger = Logger.new('log/production.log', 3, 10 * 1024 * 1024)

その後、コミット&プッシュ&デプロイを忘れずに。

90.その他知っておくこと編 #

90 − 1.再度デプロイする場合 #

資産を更新しデプロイする場合は、GitHub にプッシュした後、ローカルで再度、

bundle exec cap production deploy

を実行すれば OK.

90 − 2.サーバで本番環境の Rails c を使う方法 #

サーバ内の、

var/www/アプリケーション名/current

にて、下記を実行する。

bundle exec rails console -e production

-e production を付けずに行うと、開発環境(development)のコンソールが開かれるので注意。

コンソール上で以下を入力するとその時の環境が表示されるので、確認することも可能。

Rails.env

本番環境で開けていれば、“production"と表示される。

90 − 3.サーバで本番環境の Rails db コマンドを使う方法 #

サーバ内の以下で実施。

var/www/アプリケーション名/current

コマンドの後ろに、RAILS_ENV=production を付ける。例えば、rails db:seed なら以下。

bundle exec rails db:seed RAILS_ENV=production

ただし、本番環境の Rails db:reset したいときは以下ではダメ。

bundle exec rails db:reset RAILS_ENV=production

上記を実行すると、「ActiveRecord::ProtectedEnvironmentError: You are attempting to run a destructive action against your “production” database.」というエラーが出る。

本番環境で Rails db:reset する場合は下記を入力する。

bundle exec rails db:reset RAILS_ENV=production DISABLE_DATABASE_ENVIRONMENT_CHECK=1

他にも、本番環境の DB に破壊的なコマンドを発行するときには、DISABLE_DATABASE_ENVIRONMENT_CHECK=1 が必要。

90 − 4.ログの場所 #

本手順で構築した場合のログの格納場所。

Nginx のログはサーバ内の以下。

/var/log/nginx/
  • アクセスログ
    • /var/log/nginx/アプリケーション名_access.log
  • エラーログ
    • /var/log/nginx/アプリケーション名_error.log

Unicorn および Rails のログはサーバ内の以下。

/var/www/アプリケーション名/shared/log/
  • Unicorn のログ
    • /var/www/アプリケーション名/shared/log/unicorn.log
  • Rails のログ
    • /var/www/アプリケーション名/shared/log/production.log

以上 #

長くなったがようやく終わり。めでたしめでたし。

あとは、独自ドメインの設定、SSL 化を行い、こうしてメモを残していきたい。

*追記

次の記事を作成しました。

VPS の Rails に独自ドメインを適用し、SSL(https)化する(CentOS 8.2 / Nginx)