Help us understand the problem. What is going on with this article?

nginx + unicorn + Railsの設定方法

More than 5 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

おしまい。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away