@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
するだけ。
gem 'unicorn', '4.8.3'
設定ファイル編集
${my_app}/config
配下に以下の内容のunicornの設定ファイルを作成しておく。
# -*- 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を起動することが出来るのですが、
$ bundle exec unicorn -D -c $APP_ROOT/config/unicorn.rb -E $RAILS_ENV
いちいち手動で実行するのは面倒なので起動スクリプトを作成しました!・・・私が書いたわけではなく他のサイトから引っ張ってきたものですが。。。
#!/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.rb
のpid
で指定したpathと同じにする必要があるので注意してください。
unicorn起動/停止
以下でunicornの起動/停止が出来るようになります。
$ cd ${my_app}
$ ./script/unicorn.sh start # 起動
$ ./script/unicorn.sh stop # 停止
サブディレクトリ対応
Railsをhttp://localhost/${app_path}
のようにサブディレクトリでRailsにアクセスさせたい場合は${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
ファイルをコピーして作成しているのでいらない記述があるかも。
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
が読み込まれないので、以下のコマンドでシンボリックリンクを作成します。
$ ln -s ${nginx}/sites-available/rails_app ${nginx}/sites-enabled/rails_app
Railsの設定
Secretキーの設定
production環境でrailsを動かすためには、secretキーを設定する必要があります。
まずは以下のコマンドでsecretキーを作成します。
$ rake secret
xxxxba764fba527f6f6fa99764bb0ff8abe1edf637d0950597c11dacaea5c7f9f5903199811c86d56847086d4206f9987a3f7197651ff7e25b7c0039da75xxxx
通常は環境変数に設定するようですが、ここでは${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起動前にコンパイルして配置しておきます。
$ 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を起動します。
$ cd ${my_app}
$ ./script/unicorn.sh start
$ sudo service nginx start
今回はhttp://localhost/${app_path}
でアクセスできるはずなのでローカルのブラウザでアクセスしてみます・・・正常に設定ができていれば以下のように表示されるはずです!
ここでは${app_path}
にhogehoge
を指定しています。
おしまい。