Railsアプリケーションローカルで作成してその後、サーバーへデプロイしたい!って時ありますよね。
今回、AWSのAmazonLinux2でRailsのアプリケーションをNginxとUnicornで動作させるところまで設定したので、以下でその時に行ったことを書き残します。
動作環境は以下になります。(少しrubyとrailsのバージョンが古いですが)
$ cat /etc/system-release
Amazon Linux release 2 (Karoo)
# RDS
MySQL Community 8.0.16
$ ruby -v
ruby 2.6.0p0 (2018-12-25 revision 66547) [x86_64-linux]
$ rails -v
Rails 5.1.7
もくじ
AmazonLinux2の設定
EC2のマネジメントコンソールから、
AmazonLinuxを選択してポチポチとクリックしながら作っていきます。
こちらは、詳細はAWSのドキュメントや先人たちの参考にできるブログなどがあるので割愛します。
作成後、Railsを動作させるために以下でまとめてパッケージをインストール。
# yum update
sudo yum update -y
# gitのインストール
sudo yum install -y git
# tools for ruby on rails app dependency
sudo yum install -y gcc gcc-c++ openssl-devel readline-devel zlib-devel sqlite-devel postgresql-develop mysql-devel nodejs npm
(追記)そもそも、Windows環境からAmazonLinux環境にアクセスするための環境を整えたい、ターミナルの環境(黒背景の白文字が書かれたような画面のやつ)を準備したい!という方は以下の記事も読んでみてください。気軽にターミナルの環境を整えるのならCygwinがおすすめです。設定した後、またこの記事に戻ってきていただければ!

gitは2020年2月現在では、2.23.1がインストールされます。
$ git --version
git version 2.23.1
次にRailsを動作させるためにRubyの環境を構築します。
以下をコピペして適宜、名前をつけてシェルスクリプトとして〇〇.shなどと名前をつけて保存して実行してください。
#!/bin/bash
# 環境変数設定
# ------------------------------------------------------
# Rubyのバージョンを実行時に指定
ruby_version="$RUBY_VER"
# Railsのバージョンを実行時に指定
rails_version="$RAILS_VER"
# ------------------------------------------------------
# .bash_profileが既に存在する場合は、コピーして置き換える
cp ~/.bash_profile ~/.bash_profile.org
#rbenvをclone
git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
#cloneできたらrbenvのPATHを通す
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
source ~/.bash_profile
#rbenvが使えるか確認
rbenv --version
#rbenvを使用してRubyをインストール
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
#インストールできるRubyのバージョンを確認する
rbenv install --list
#rubyのバージョンを指定してインストール(例:2.6.5)
rbenv install "${ruby_version}"
#インストールできたら、Rubyを 指定したversion に切り替える
rbenv global "${ruby_version}"
rbenv rehash
#バージョンを確認する
ruby -v
# ------------------------------------------------------
#bundlerのインストール
gem install bundler
rbenv rehash
# ------------------------------------------------------
# Railsのインストール
#バージョン指定してインストール(例:5.2.4)
gem install -v "${rails_version}" rails
#Railsがインストールできたか確認
rails -v
以下のように実行します。
RUBY_VER=2.6.0 RAILS_VER=5.1.7 sh [適宜の名前].sh
Rubyのインストールは結構時間かかります。気長に待ちましょう。
Railsアプリのgit clone
作成したRialsアプリをgithubなどのリポジトリで管理している場合は、git cloneして本番環境へ設置します。
僕は、/home/ec2-user/workspaceというディレクトリを作成して、
その配下にgit cloneしました。
sshの設定が必要になってきますが、sshの設定については
また今度書いてみたいと思います。
(追記)GitHubとsshの設定について記事を書きました。

git cloneしてきたら、bundle install を実行します。
cd /home/ec2-user/workspace/[railsのアプリのルート]
bundle install
gemが無事にインストールできたら、RDSの作成に移ります。
RDSの作成
今回、AWS環境でRailsを動作させるので、データベースはRDSを使います。
RDSの作成については、割愛しますが、注意点として、
RDSインスタンスへ割り当てるセキュリティグループのインバウンドのルールに
- Postgresqlを使用するなら、5432番の通信を許可する設定
- MySQLを使用するなら、3306番の通信を許可する設定
を追加してください。
RDSインスタンスをそのままマネジメントコンソールでポチポチと作成していくと、セキュリティグループはデフォルトのものが設定されている状態になっているので、EC2からRDSのデータベースへ接続する際にTCPでの通信に失敗します。
RDSを作成したら、接続ができるかどうかを確認します。
mysql -u [RDSを作成する際に設定したユーザ] -p -h [RDSのエンドポイント名]
今回は、本番環境のデータベースとして、MySQLを使用します。
なので、RailsのGemfileのproductionの箇所に以下を追記してbundle installします。
group :production do
gem 'mysql2'
end
Railsのconfig/database.ymlを変更する
本番環境で動作させることを想定して、database.ymlのproductionの箇所を編集します。
production:
<<: *default
adapter: mysql2
database: [データベース名]
encodign: utf8
reconect: false
username: [RDSを作成した際のユーザ名]
password: [RDSを作成した際のパスワード]
socket: /var/lib/mysql/mysql.sock
host: [RDSのエンドポイント名]
RailsのコマンドでDBを作成する
Railsアプリのルートで以下を実行します。
bundle exec rails db:create RAILS_ENV=production
これでデータベースが作成されます。
データベースを作成できたら、マイグレーションを実行します。
bundle exec rails db:migrate RAILS_ENV=production
seacret_key_baseの設定
ここで、rails severを起動したいところですが、Railsはproduction環境で動作させようとすると、config/secrets.ymlで設定してある、
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
この部分でseacret_key_baseの値を環境変数を見に行っているので、何も設定していなければ、ブラウザからアクセスしても、
An unhandled lowlevel error occurred. The application logs may have details.
と表示されて、railsで作成したアプリケーションのトップページが表示されません。
なので、以下のコマンドでproduction環境で動作させるためのseacret_key_baseの値を生成します。
bundle exec rails secret
実行するとハッシュ値らしき値が生成されるので、その値を環境変数へ設定します。
export SECRET_KEY_BASE=[先程生成された値]
Railsのアセットパイプラインを構築し直す
以下のコマンドを入力して、Railsのアセットパイプラインをproduction環境で構築します。
rake assets:precompile RAILS_ENV=production
こちらを実行していないと、サーバーを立ち上げたRailsアプリへアクセスしても、
We're sorry, but something went wrong.
If you are the application owner check the logs for more information.
などと表示されてしまいます。
一旦Railsのサーバーを立ち上げてアプリのトップページが表示されるか確認しておく
ここまで設定を終えていれば、Railsのアプリケーションサーバーを立ち上げて作成したRailsのアプリケーションが意図した通りに表示されるかを確認しておく。
以下のコマンドでRailsのアプリケーションサーバーを起動。
bundle exec rails s -e production
http://EC2インスタンスのIPアドレス:3000
でアクセスすれば無事にRailsアプリのトップページが表示されるはず。
nginxとunicornでRailsを動作させる
unicornの設定
Railsをデフォルトのアプリケーションサーバーを起動してアクセスさせることができたら、次にNginxとUnicornで動作させる設定を行う。
Gemfileに以下の追記をします。追記したら、bundle installを実行。
group :production do
gem 'mysql2'
gem 'unicorn', '5.4.1'←追記
end
config/unicorn.rb として、unicornの設定を記述します。
upstream unicorn {
server unix:/home/ec2-user/workspace/[railsアプリケーションのルート]/tmp/sockets/unicorn.sock;
}
server {
listen 80;
server_name [EC2インスタンスのIPアドレス];
access_log /var/log/nginx/sample_access.log;
error_log /var/log/nginx/sample_error.log;
root /home/ec2-user/workspace/[railsアプリケーションのルート]/public;
client_max_body_size 100m;
error_page 404 /404.html;
error_page 500 502 503 504 /500.html;
try_files $uri/index.html $uri @unicorn;
location @unicorn {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_pass http://unicorn;
}
}
上記を記述すれば、unicornを、「bundle exec unicorn_rails -c config/unicorn.rb -E production -D」として、実行すれば起動することができますが、いちいちこのコマンドを入力して起動させるのも面倒なので、rakeタスクを作成します。
bundle exec rails generate task unicorn
lib/tasks/unicorn.rakeが作成されるので、以下の内容に編集。
namespace :unicorn do
##
# Tasks
##
desc "Start unicorn for production env."
task(:start) {
config = Rails.root.join('config', 'unicorn.rb')
sh "bundle exec unicorn_rails -c #{config} -E production -D"
}
desc "Stop unicorn"
task(:stop) { unicorn_signal :QUIT }
desc "Restart unicorn with USR2"
task(:restart) { unicorn_signal :USR2 }
desc "Increment number of worker processes"
task(:increment) { unicorn_signal :TTIN }
desc "Decrement number of worker processes"
task(:decrement) { unicorn_signal :TTOU }
desc "Unicorn pstree (depends on pstree command)"
task(:pstree) do
sh "pstree '#{unicorn_pid}'"
end
def unicorn_signal signal
Process.kill signal, unicorn_pid
end
def unicorn_pid
begin
File.read("/home/ec2-user/workspace/[railsのルート]/tmp/pids/unicorn.pid").to_i
rescue Errno::ENOENT
raise "Unicorn doesn't seem to be running"
end
end
end
Unicornを起動したければ、
bundle exec rake unicorn:start
停止したければ、
bundle exec rake unicorn:stop
を実行できるようになります。
nginxの設定
AmazonLinux2では、デフォルトのyumパッケージでは、Nginxは配布されていないので、amazon-linux-extras からインストールする。
sudo amazon-linux-extras install nginx1
/etc/nginx/conf.d/以下に、unicorn独自の設定を作っていく。
sudo vim /etc/nginx/conf.d/[railsのアプリ名].conf
以下のように書いて保存
upstream unicorn {
server unix:/home/ec2-user/workspace/[railsアプリのルート]/tmp/sockets/unicorn.sock;
}
server {
listen 80;
server_name [EC2インスタンスのIPアドレス];
access_log /var/log/nginx/sample_access.log;
error_log /var/log/nginx/sample_error.log;
root /home/ec2-user/workspace/[railsアプリのルート]/public;
client_max_body_size 100m;
error_page 404 /404.html;
error_page 500 502 503 504 /500.html;
try_files $uri/index.html $uri @unicorn;
location @unicorn {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_pass http://unicorn;
}
}
nginxの設定で文法などのエラーがないかを確認しておく。
sudo nginx -t
OKなどと返ってくればちゃんと設定できています。
unicornとnginxを起動させてRailsアプリへアクセス
以下のコマンドを実行し、unicornとnginxを動作させる。
bundle exec rake unicorn:start
sudo systemctl start nginx
http://EC2のIPアドレスへアクセスして、動作確認。
「502 bat gateway」と表示される場合は、 /var/log/nginx/sample_error.logの中身を確認してみる。
「13: Permission denied」などと表示されている場合は、nginxのプロセスを実行しているユーザーとunicornを実行しているユーザーが異なるため、unicorn.sockへのアクセス権限でファイルへのアクセスが拒否されている可能性がある。
対応策としては、
- ファイルへのアクセス権を設定してworkerプロセス起動ユーザーがsockファイルへアクセスできるように設定する
- nginxのworkerプロセス起動ユーザーをsockファイルへのアクセス権があるユーザーへ変更する
という手段が考えられるが、
今回は、2つ目の対応を行う。
nginxのworkerを動作させているユーザーは以下のコマンドで確認できる。
ps aux | grep nginx
root 3879 0.0 0.2 121484 2216 ? Ss 16:01 0:00 nginx: master process /usr/sbin/nginx
nginx 3881 0.0 0.4 121968 4904 ? S 16:01 0:00 nginx: worker process ←これがworkerプロセス。nginxユーザーが動作させていることがわかる
ec2-user 3914 0.0 0.0 119436 920 pts/0 S+ 16:08 0:00 grep --color=auto nginx
unicornについては、ec2-userで起動させているので、
nginxのプロセスを実行するユーザーをec2-userへ変更する。
sudo vim /etv/nginx/nginx.conf
以下を編集する。
# For more information on configuration, see:
# * Official English Documentation: http://nginx.org/en/docs/
# * Official Russian Documentation: http://nginx.org/ru/docs/
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
↓以下に変更。
#user nginx; ←コメントアウトして、
user ec2-user; ←追記
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
そして、nginxを再起動。
sudo systemctl restart nginx
これで、http://EC2のIPアドレス
へアクセスすると、Railsアプリのトップページが表示されるはず。
僕自身は、この設定でめっちゃドハマリました。
nginxでエラーが出て調査するにもログが吐き出されていなかったり、
unicorn個別の設定を書いている時に、80番ポートでの設定に、default_severの設定を書いていて、重複しているとnginx -tで検証した時に怒られたりしました。
今回は、「とにかくサーバー上で、動作させる」という点を重視して設定したので、
セキュリティの設定については、もっと強固なやり方があるはずです。
どこまでやるかは、各プロジェクトの方針に従ったほうがいいと思います。
Rails勉強中の誰かの参考になれば幸いです。
🤦♂️公務員から転職したくて悩んでる
🤦♀️でも身近に相談できる人が居ない
🤦♂️家族には相談できない…
🤦♀️ちょっと話を聞いてもらいたい…
とお悩みのあなた!
もとろぐに相談してみませんか?
僕に人生を前進させるお手伝いをさせてください。LINEでお待ちしております🙋♂️
※すぐにブロックしていただいても大丈夫ですので、お気軽にお問い合わせください☺