ウェブサービスを作っています。

nginx + Unicorn を試してみた

追記(2012/02/21 09:39):
nginx 設定ファイルの例に、X-Frame-Options, X-Content-Type-Options に関する設定を加筆しました。


追記(2011/10/17 19:18):
Rails 3.1 用に、nginx 設定ファイルの例を加筆・修正しました。


追記(2010/09/25 12:07):
現在はさくらの VPS を使用しています。


追記(2010/08/16 11:18):
nginx 設定ファイルの例に root 文を書き忘れていたので追加しました。


話題の Unicorn を試してみました。


Unicorn については、以下の記事が詳しいです。
次世代Ruby on RailsサーバーUnicorn(汎用のRackアプリケーションサーバ)を使ってみた | TechRacho


現在 PONPON は nginx + Unicorn で動いています。(サーバは saases のメモリ 512MB VPS、月 450 円)
OS は debian lenny です。delayed_job を使うようになった関係で Heroku だとコストが高くなってしまいます..


まず apache をとめて nginx と Unicorn を入れます。

# /etc/init.d/apache2 stop
# update-rc.d -f apache2 remove
# aptitude install nginx
# gem install unicorn


RAILS_ROOT に移って、Unicorn の設定ファイルを書きます。

# ワーカーの数
worker_processes 2

# capistrano 用に RAILS_ROOT を指定
working_directory "/home/milk1000cc/example/current"

# ソケット
listen '/tmp/unicorn_of_example.sock'

# ログ
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

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
      # SIGTTOU だと worker_processes が多いときおかしい気がする
      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


Unicorn を動かします。

% cd RAILS_ROOT
% unicorn_rails -c config/unicorn.rb -E production -D

-E で環境指定、-D でデーモン化ですね。


nginx 設定ファイルを書きます。

upstream unicorn-of-example {
  server unix:/tmp/unicorn_of_example.sock;
}

server {
  listen 80;
  server_name www.example.com;
  rewrite ^/(.*) http://example.com/$1 permanent;
}

server {
  listen 80;
  server_name example.com;

  # http://blog.monoweb.info/article/2012021823.html
  add_header X-Frame-Options DENY;
  add_header X-Content-Type-Options nosniff;

  root /home/milk1000cc/example/current/public;
  error_log /home/milk1000cc/example/current/log/error.log;

  location / {
    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_redirect off;
    if (!-f $request_filename) { proxy_pass http://unicorn-of-example; }
  }

  location ~* \.(ico|css|js|gif|jpe?g|png)(\?[0-9]+)?$ {
    expires 1y;
    add_header Cache-Control public;

    # http://guides.rubyonrails.org/asset_pipeline.html#server-configuration
    add_header Last-Modified "";
    add_header ETag "";
  }

  # for Rails3.1
  # location ~ ^/assets|system/ {
  #   expires 1y;
  #   add_header Cache-Control public;

  #   add_header Last-Modified "";
  #   add_header ETag "";
  # }
}


スタート。

# ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/example.com
# /etc/init.d/nginx restart


Passenger と比べて圧倒的に良いかといわれると微妙なのですが、ダウンタイムがなくなるのは良いです。