nginx+UnicornでRailsのページキャッシュを使おうとしてはまった話

ここここを参考に設定してみたが、nginx+Unicornの組み合わせでページキャッシュが効かなかったので、ちょっと試行錯誤。

最終的には以下を参考にしてなんとかなった。

原因

nginxがキャッシュファイルを見つけてくれなかった

状況を調べてみるとキャッシュファイル自体は作られている。

しかしRailsがキャッシュファイルを作るときにパス名に「index.html」か「.html」を付加したものをファイル名とするが、nginxはこの事情を知らないので、キャッシュファイルを見つけられなかった。

なので都度Unicornの方へリクエストを振っていた。

一方Unicornは静的ファイルへのアクセスをnginxに一任していた

Rails3からはProduction環境ではデフォルトで静的ファイルへのアクセスを受け付けていない。

以下デフォルトのconfig/environments/production.rbより抜粋。

  # Disable Rails's static asset server
  # In production, Apache or nginx will already do this
  config.serve_static_assets = false

RailsをWebrickなりUnicornなりのサーバー単体で動かすことはすでに期待してないらしい。

てっきりnginxがキャッシュを返してくれなくても、Unicornがキャッシュを返すはずと思っていたが、そうではなかったという話。

解決策

以下のいずれか片方を実施すればよい。

  • nginxがRailsのキャッシュファイルを見つけられるようにしてやる
  • Unicornが静的ファイルへのアクセスを受け付けるようにする

前者の方が無駄が少ない。Railsのレールはおそらくこちらに向かっている。
後者はどちらかと言えばRailsをサーバー単体で動かす場合のオプションだろう。

設定ファイル

最終的には以下のように落ち着いた。

upstream unicorn-of-example {
  server www.example.com:8080;
}

server {
  listen 80;  
  server_name www.example.com

  root /var/www/example/current/public;
  error_log /var/www/example/current/log/error.log;

  try_files $uri $uri.html $uri/index.html @unicorn;

  location @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_redirect off;
    proxy_pass http://unicorn-of-example;
  }
}

ちょっと解説。

  try_files $uri $uri.html $uri/index.html @unicorn;

try_filesは指定されたファイルが存在するかどうかを左から順番にチェックして、ファイルが存在すればnginx自身がそれを返す。
存在しなければ最後に指定されたURIにアクセスする。

「index.html」と「.html」はRailsがページキャッシュするときにファイル名に付け加えるもの。

  location @unicorn {

@unicornの代わりに「/」でも問題はないようだ。try_filesでの指定と共通している必要はある。

次の記事

WheneverでRailsのバッチ処理