2013/10/01

Redmine を Nginx + Unicorn で動かす

前回までのあらすじ


Nginx を Apache のリバースプロキシに設定した。

今日の目標

現在 Apache + Passenger で動いている Rails アプリの Redmine を Nginx + Unicorn に切り替えてみよう。
Redmine は /var/www/redmine に設置されている。

Gem の追加

Redmine の gem に unicorn を追加する。
もしRedmine本体は使用しないgem(例: mongrel, fcgi)もロードしたい場合、 Gemfile.local というファイルをRedmineのディレクトリに作成してください。
Redmineのインストール — Redmine Guide 日本語訳

ということなので Gemfile.local を作成した。
# Gemfile.local
gem "unicorn"

インストール。
$ bundle install

Unicorn の設定

Redmine の config ディレクトリに unicorn.rb というファイルを作成した。

worker_processes 1

timeout 60

listen File.expand_path("tmp/sockets/unicorn.sock", ENV['RAILS_ROOT'])

pid File.expand_path("tmp/pids/unicorn.pid", ENV['RAILS_ROOT'])

stdout_path File.expand_path("log/unicorn.stdout.log", ENV['RAILS_ROOT'])
stderr_path File.expand_path("log/unicorn.stderr.log", ENV['RAILS_ROOT'])

preload_app true
GC.respond_to?(:copy_on_write_friendly=) and GC.copy_on_write_friendly = true

before_fork do |server, worker|
# この設定はpreload_app trueの場合に必須
defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!

# USR2シグナルで旧プロセスを終了させる
old_pid = "#{server.config[:pid]}.oldbin"
if old_pid != server.pid
begin
sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU
Process.kill(sig, File.read(old_pid).to_i)
rescue Errno::ENOENT, Errno::ESRCH
end
end
end

after_fork do |server, worker|
# この設定はpreload_app trueの場合に必須
defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
end

とりあえず socket のパス。これ大事。
tmp/sockets/unicorn.sock

pid のパス。これも大事。
tmp/pids/unicorn.pid

Unicorn 起動


え、Unicorn て Apache とか Nginx とかとは別口で起動しておかないといけないの?
後で自動化できないか調べなきゃ。
$ bundle exec unicorn_rails -c config/unicorn.rb -D -E production

コマンドのオプションは -c で設定ファイル指定、-E で動作モード指定、-D がデーモン化。
終了の仕方は力ずく。
$ kill -quit 'cat /var/www/redmine/tmp/pids/unicorn.pid'

Nginx の設定


/etc/nginx/sites-available/ に設定ファイルを作成して /etc/nginx/sites-enabled/ からリンクを張る。
upstream redmine {
server unix:/var/www/redmine/tmp/sockets/unicorn.sock;
}

server {
listen 80;
server_name redmine.tepidworks.jp;

location / {
root /var/www/redmine/public;

if ( -f $request_filename ) { break; }

proxy_set_header X-Real-IP  $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_pass http://redmine;
}
}

if ( -f $request_filename ) { break; } があるので、静的ファイルへのアクセスは Rails を通さないで Nginx が直接返す。*1

Nginx 再起動

$ sudo service nginx restart

無事アクセスできた。

*1:少なくとも、確認した限り静的ファイルへのアクセスでは Rails がログを吐かなかったので Unicorn に処理は渡っていないはず。