Rails(Apache+Unicorn)で、public以下のディレクトリの中身が404になる場合の解決策


そもそもは、GitLabのGroup Avaterがリンク切れになっていて、調査したところ、どうやらファイル自体はアップロードされているものの、ファイル自体を参照しようとすると404になってた、というのが発端です。その対応ログです。

ちなみに、

  • RailsのVersion ~> 4.1.0
  • Webサーバ Apache
  • Applicationサーバ Unicorn

の構成です。

解決策1(応急処置)

対策自体は、config/environments/production.rbの1行を、以下のように修正し、再起動するだけで解決しました。

production.rb
# Disable Rails's static asset server (Apache or nginx will already do this)
- config.serve_static_assets = false
+ config.serve_static_assets = true

コメントにもあるように、基本的に、static assetsについては、ApacheやNginxのようなWebサーバが行ってくれるはずですが、なぜいけなかったのでしょうか?

原因

参考URLにある通り、どうやら、WebサーバであるApacheがpublic/uploads/*をプロキシしても、ApplicationサーバであるUnicornが処理しないのが原因のようです。(設定でそのようにしているのだから当たり前ですね。)

the problem is apache will proxy the derectory "uploads/*" to unicorn
but unicorn won't deal with the request because this
config.serve_static_assets = faules in "config/environments/production.rb"

最初に行った対策で、Apacheからstatic assetsが配信されるようになるのですが、それだと、Unicornの負荷が上がってしまいそうです。(Webサーバを使っている場合、static assetsをApplicationサーバに処理させるのは非推奨のようです。)

なので、根本的には、config.serve_static_assets = falseとして、static assetsはApacheから配信されるように設定し、役割を分けることがより適切な対応となります。

解決策2

現時点では、public/uploads/*は、Unicornに処理されています。

production.log
Processing by NamespacesController#show as HTML
  Parameters: {"id"=>"uploads/group/avatar/**/logo.png"}
Completed 404 Not Found in 10ms (Views: 4.5ms | ActiveRecord: 0.7ms)

これを解決するには、リバースプロキシの設定で、public以下のupload/*のリクエストは、Webサーバが処理するように設定を追記します。

gitlab.conf
#########################################
# Reverse Proxy Settings (GitLab Service)
ProxyPass /uploads ! # <- This is it!
ProxyPass / http://localhost:8080/
ProxyPassReverse / http://localhost:8080/
ProxyPreserveHost on

これでWebサーバを再起動すれば、晴れて'public/uploads/*`以下のstatic assetsがApacheで処理されるようになります。

access_log
XXX.XXX.XXX.XXX - - [12/Nov/2014:12:54:50 +0900] "GET /uploads/group/avatar/XX/logo.png HTTP/1.1" 301 366 "-" "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.111 Safari/537.36"

まとめ

Apacheでpublic以下の任意のディレクトリの中身を処理させたい場合、リバースプロキシの設定を追加する必要がある。

References