Rails
nginx

nginx + unicorn + Railsの設定方法

More than 3 years have passed since last update.

@aki1986です。

何回かに分けて「nginx + unicorn + rails」の連携方法を記載していこうと思います。

今回はnginx連携(最後)まで!


背景

監視サイトのダッシュボードを構築することとなり、どうせならrailsでどうせならnginx上で動かすかと思い立ち構築してみた。

今回は前回書いたRailsインストール以降の設定方法について書きます。

nginxのインストール方法はここでは書きません。

環境は以下。


  • ubuntu: 12.04

  • ruby: 2.1.2p95

  • Rails: 4.1.4

  • nginx: nginx/1.1.19

  • unicorn: 4.8.3


Unicorn設定

Railsとnginxはunicorn経由でやり取りさせる。

以下のイメージ。

nginx <-> unicorn <-> Rails


Unicornインストール

インストールと言ってもRailsアプリ${my_app}のGemfileに以下を追記して、$ bundle installするだけ。


${my_app}/Gemfile

gem 'unicorn', '4.8.3'



設定ファイル編集

${my_app}/config配下に以下の内容のunicornの設定ファイルを作成しておく。


${my_app}/config/unicorn.rb

# -*- coding: utf-8 -*-

# ワーカーの数
worker_processes 2

# ソケット
listen '/tmp/unicorn.sock'
pid '/tmp/unicorn.pid'

# ログ
log = '${my_app}/log/unicorn.log'
stderr_path File.expand_path('log/unicorn.log', ENV['RAILS_ROOT'])
stdout_path File.expand_path('log/unicorn.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|
defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!

old_pid = "#{ server.config[:pid] }.oldbin"
unless old_pid == server.pid
begin
sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU
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


listen pidのpathはご自身の環境に即したpathを指定してください。

またENV['RAILS_ROOT']で環境変数としてRailsのアプリケーションディレクトリを指定していますが、環境変数で指定するほどでもない場合はs/ENV['RAILS_ROOT']/${my_app}/gとして直書きでもよいかと思います。


起動スクリプト作成

以下のコマンドでunicornを起動することが出来るのですが、


exec_unicorn

$ bundle exec unicorn -D -c $APP_ROOT/config/unicorn.rb -E $RAILS_ENV


いちいち手動で実行するのは面倒なので起動スクリプトを作成しました!・・・私が書いたわけではなく他のサイトから引っ張ってきたものですが。。。


unicorn_script

#!/bin/bash

set -e

TIMEOUT=${TIMEOUT-60}
APP_ROOT=${my_app}
PID=/tmp/unicorn.pid
#RAILS_ENV=production
RAILS_ENV=development
CMD="bundle exec unicorn -D -c $APP_ROOT/config/unicorn.rb -E $RAILS_ENV"
action="$1"
set -u

old_pid="$PID.oldbin"

cd $APP_ROOT || exit 1

sig () {
test -s "$PID" && kill -$1 `cat $PID`
}

oldsig () {
test -s $old_pid && kill -$1 `cat $old_pid`
}

case $action in
start)
sig 0 && echo >&2 "Already running" && exit 0
$CMD
;;
stop)
sig QUIT && rm -f ${PID} && exit 0
echo >&2 "Not running"
;;
force-stop)
sig TERM && exit 0
echo >&2 "Not running"
;;
restart|reload)
sig HUP && echo reloaded OK && exit 0
echo >&2 "Couldn't reload, starting '$CMD' instead"
$CMD
;;
upgrade)
if sig USR2 && sleep 2 && sig 0 && oldsig QUIT
then
n=$TIMEOUT
while test -s $old_pid && test $n -ge 0
do
printf '.' && sleep 1 && n=$(( $n - 1 ))
done
echo

if test $n -lt 0 && test -s $old_pid
then
echo >&2 "$old_pid still exists after $TIMEOUT seconds"
exit 1
fi
exit 0
fi
echo >&2 "Couldn't upgrade, starting '$CMD' instead"
$CMD
;;
reopen-logs)
sig USR1
;;
*)
echo >&2 "Usage: $0 <start|stop|restart|upgrade|force-stop|reopen-logs>"
exit 1
;;
esac


上記でPID=/tmp/unicorn.pidについてですが、これは${my_app}/config/unicorn.rbpidで指定したpathと同じにする必要があるので注意してください。


unicorn起動/停止

以下でunicornの起動/停止が出来るようになります。


exec_script

$ cd ${my_app}

$ ./script/unicorn.sh start # 起動
$ ./script/unicorn.sh stop # 停止


サブディレクトリ対応

Railsをhttp://localhost/${app_path}のようにサブディレクトリでRailsにアクセスさせたい場合は${my_app}/config.ruにさらに以下の設定が必要です。


${my_app}/config.ru

# This file is used by Rack-based servers to start the application.

RAILS_RELATIVE_URL_ROOT="/${app_path}"
require ::File.expand_path('../config/environment', __FILE__)
if RAILS_RELATIVE_URL_ROOT then
map RAILS_RELATIVE_URL_ROOT do
run Rails.application
end
else
run Rails.application
end


nginx設定


site-availableファイルの作成

以下のようなファイルを${nginx}/site-available/配下に作成します。

defaultファイルをコピーして作成しているのでいらない記述があるかも。


${nginx}/site-available/rails_app

upstream rails-unicorn {

server unix:/tmp/unicorn.sock;
}

server {
#listen 80; ## listen for ipv4; this line is default and implied
#listen [::]:80 default ipv6only=on; ## listen for ipv6

# root /usr/share/nginx/www;
index index.php index.html index.htm;

# Make site accessible from http://localhost/
server_name localhost;

location /${app_path}/ {
try_files $uri $uri.html $uri/index.html @rails-unicorn;
}
location ~ ^/assets/(.*) {
alias ${my_app}/public/assets/$1;
}

location @rails-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://rails-unicorn;
}

# Only for nginx-naxsi : process denied requests
#location /RequestDenied {
# For example, return an error code
#return 418;
#}

error_page 404 /404.html;

# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/www;
}

}


upstream rails-unicorn {}でunicornのソケットファイルを指定しています。

またlocation ~ ^/assets/(.*) {}では、cssファイル、jsファイルの検索パスを指定しています。

Railsのデフォルトのdevelopment環境ではこの指定は不要なのですが、production環境では速度的な観点でデフォルトで${my_app}/config/environments/production.rbの中でconfig.assets.compile = falseを指定しているため動的にcssファイル、jsファイルを作成しないようになっています。

そのためRailsアプリケーションでロジックが必要なものは、nginx <-> unicorn <-> railsという流れで、css、jsファイルの読み込みはnginx <-> css, jsファイルという流れとなっています。(多分。。。)


シンボリックリンクの作成

このままではnginx起動時に作成した${nginx}/site-available/rails_appが読み込まれないので、以下のコマンドでシンボリックリンクを作成します。


symbolic_link

$ ln -s ${nginx}/sites-available/rails_app ${nginx}/sites-enabled/rails_app



Railsの設定


Secretキーの設定

production環境でrailsを動かすためには、secretキーを設定する必要があります。

まずは以下のコマンドでsecretキーを作成します。


create_secret_key

$ rake secret

xxxxba764fba527f6f6fa99764bb0ff8abe1edf637d0950597c11dacaea5c7f9f5903199811c86d56847086d4206f9987a3f7197651ff7e25b7c0039da75xxxx

通常は環境変数に設定するようですが、ここでは${my_app}/config/secrets.ymlを以下のように直接編集します。


${my_app}/config/secrets.yml

# Do not keep production secrets in the repository,

# instead read values from the environment.
production:
secret_key_base: xxxxba764fba527f6f6fa99764bb0ff8abe1edf637d0950597c11dacaea5c7f9f5903199811c86d56847086d4206f9987a3f7197651ff7e25b7c0039da75xxxx


assetsファイルの作成

cssファイルやjsファイルをrails起動前にコンパイルして配置しておきます。


create_assets

$ bundle exec rake assets:precompile

I, [2014-08-13T14:24:42.887465 #11940] INFO -- : Writing ${my_app}/application-xxxxxxxxxxxxxx.js
I, [2014-08-13T14:24:42.887465 #11940] INFO -- : Writing ${my_app}/application-xxxxxxxxxxxxxx.css


動作確認

さていよいよ動作確認。

以下のコマンドでunicornとnginxを起動します。


start_service

$ cd ${my_app}

$ ./script/unicorn.sh start
$ sudo service nginx start

今回はhttp://localhost/${app_path}でアクセスできるはずなのでローカルのブラウザでアクセスしてみます・・・正常に設定ができていれば以下のように表示されるはずです!

ここでは${app_path}hogehogeを指定しています。

img_nginx_access.png

おしまい。