VPS のサーバーを移行したついでに Web サーバーを Apache から Nginx へ、Rails アプリの実行環境を Passenger から Unicorn へ移行する事にした。その影響でいろいろ設定などを書き換える必要があったのでメモ代わりに書いておこうと思う。
Rails アプリを Unicorn で動くようにする
Gemfile で unicorn を読み込むようにする
$ vim Gemfile
group :production do
gem 'unicorn'
end
unicorn の設定ファイルを config/unicorn.rb に記述する。
$ vim config/unicorn.rb
APP_PATH = "#{File.dirname(__FILE__)}/.." unless defined?(APP_PATH)
RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT)
RAILS_ENV = ENV['RAILS_ENV'] || 'development'
shared_path = '/home/ryomatsu/projects/example/shared'
worker_processes 3
listen "/tmp/example-com.sock"
pid "#{shared_path}/tmp/pids/unicorn.pid"
preload_app true
timeout 60
working_directory APP_PATH
# log
stderr_path "#{RAILS_ROOT}/log/unicorn_error.log"
stdout_path "#{RAILS_ROOT}/log/unicorn_access.log"
if GC.respond_to?(:copy_on_write_friendly=)
GC.copy_on_write_friendly = true
end
before_exec do |server|
ENV['BUNDLE_GEMFILE'] = APP_PATH + "/Gemfile"
end
before_fork do |server, worker|
defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!
old_pid = "#{ server.config[:pid] }.oldbin"
unless 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
特に重要なのが pid と sock ファイルの場所。これらを利用して Unicorn の起動や停止、Nginx からの読み込みを行う。
Unicorn の起動は以下のコマンドで行える。
$ bundle exec unicorn_rails -c config/unicorn.rb -E production -D
それから Apache では設定ファイル内に記述していた secret_key_base の記述もどこかにしておく。dotenv Gem を利用するのが良いらしいがとりあえず動作すればよいので config/secrets.yml に直接書いてしまった。後でどうにかするかも。
Unicorn で動く Rails アプリを Capistrano でデプロイする
自分の Rails アプリケーションは全て Capistrano を利用してデプロイしているため、Capfile や deploy.rb などを書き換える。
Capistrano を使って Rails アプリをデプロイするunicorn を利用する際は capistrano3-unicorn Gem を利用すると楽っぽい。
GitHub - tablexi/capistrano3-unicornGemfile に gem 'capistrano3-unicorn'
を記述し bundle install
でインストール、Capfile では capistrano3-unicorn を読み込むようにする。
$ vim Gemfile
# 以下を追記
gem 'capistrano3-unicorn'
$ vim Capfile
# 以下を追記
require 'capistrano3/unicorn'
次に config/deploy.rb を編集する。
$ vim config/deploy.rb
# 以下適当な場所に追記しておく。
set :unicorn_roles, ->{ :web }
set :unicorn_pid, "#{shared_path}/tmp/pids/unicorn.pid"
set :unicorn_config_path, -> { File.join(current_path, "config", "unicorn.rb") }
after 'deploy:published', 'deploy:restart'
namespace :deploy do
desc 'Restart application'
task :restart do
on roles(:web), in: :sequence, wait: 5 do
#invoke 'unicorn:restart'
invoke 'unicorn:stop'
invoke 'unicorn:start'
end
end
end
capistrano3-unicorn では標準では role が :app のサーバーに対してのみ unicorn のタスクが実行できるようなので unicorn_roles で指定しておく。
pid は unicorn を再起動するのに必要となるので path を間違えないように。人によって shared/tmp/pids/ と current/tmp/ とで設定方法が分かれる。
本来は unicorn:restart を実行すると unicorn.pid を利用して kill -s USR2 コマンドを実行し unicorn が再起動されるはずなのだが、なんか上手くいかなかったので unicorn:stop と unicorn:start コマンドを実行している。
Nginx + Unicorn で Rails アプリを動かす
最後に Nginx で Unicorn を介して Rails アプリを動かすように設定しよう。例えば以下のような感じになる。
$ vim /etc/nginx/sites-available/example.com
upstream example-com {
server unix:/tmp/example-com.sock;
}
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
server {
listen 443;
ssl on;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
server_name example.com;
access_log /var/log/nginx/example.com-access.log;
error_log /var/log/nginx/example.com-error.log;
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Client-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_pass http://example-com;
}
location ~ ^/assets/ { root /home/ryomatsu/public_html/example.com/public; }
location ~ ^/images/ { root /home/ryomatsu/public_html/example.com/public; }
location ~ ^/uploads/ { root /home/ryomatsu/public_html/example.com/public; }
location = /robots.txt { log_not_found off; }
location = /favicon.ico { log_not_found off; }
}
$
$
$ sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
$ sudo nginx -t
$ sudo systemctl restart nginx
一番上の upstream で Rails アプリ内で指定した sock ファイルと同じものを指定し、それを proxy_pass で渡す。そうすれば Nginx が Unicorn を経由して Rails アプリにアクセスできる。
assets や images などへアクセスする際には location で場所を指定する必要があったのでそれも記述している。
これで再起動して設定ファイルを読み込めば Web ブラウザから Rails アプリにアクセスできるはず。
正常に動作しない場合は nginx のログ /var/log/nginx/example.com-error.log
や、unicorn のログ log/unicorn_error.log
を確認しよう。
-- 参考リンク
capistrano3-unicorn/unicorn.rb at master · tablexi/capistrano3-unicorn · GitHub
Rails4+Capistrano3+Nginx+Unicorn EC2へのデプロイ < 前編 > - Qiita
Unicorn + nginx で複数の Rails アプリを動かす : あかぎメモ