Sinatra を使って https で動作する nginx サーバーがあります。Mongrel と http (s なし) で問題なく動作する構成で jnlp ファイルをダウンロードしようとすると、nginx サーバーは 504 エラーでファイルを提供できません。その後のログの確認では、このエラーは使用可能なファイル ハンドルの数のオーバーフロー、つまり「24: 開いているファイルが多すぎます」が原因であることがわかります。
sudo lsof -p <nginx worker pid>
次のような膨大なファイルリストが表示されます:
nginx 1771 nobody 11u IPv4 10867997 0t0 TCP localhost:44704->localhost:https (ESTABLISHED)
nginx 1771 nobody 12u IPv4 10868113 0t0 TCP localhost:https->localhost:44704 (ESTABLISHED)
nginx 1771 nobody 13u IPv4 10868114 0t0 TCP localhost:44705->localhost:https (ESTABLISHED)
nginx 1771 nobody 14u IPv4 10868191 0t0 TCP localhost:https->localhost:44705 (ESTABLISHED)
nginx 1771 nobody 15u IPv4 10868192 0t0 TCP localhost:44706->localhost:https (ESTABLISHED)
nginx 1771 nobody 16u IPv4 10868255 0t0 TCP localhost:https->localhost:44706 (ESTABLISHED)
nginx 1771 nobody 17u IPv4 10868256 0t0 TCP localhost:44707->localhost:https (ESTABLISHED)
nginx 1771 nobody 18u IPv4 10868330 0t0 TCP localhost:https->localhost:44707 (ESTABLISHED)
nginx 1771 nobody 19u IPv4 10868331 0t0 TCP localhost:44708->localhost:https (ESTABLISHED)
nginx 1771 nobody 20u IPv4 10868434 0t0 TCP localhost:https->localhost:44708 (ESTABLISHED)
開くことができるファイルの数を増やしても、nginx がその制限をすぐに超えてしまうため、役に立ちません。利用可能なすべてのファイルを取得するために、何らかのループが発生しているように見えるのも不思議ではありません。
何が起こっているのか、またそれをどう修正すればよいのか、何かご存知ですか?
編集:nginx 0.7.63、Ubuntu Linux、Sinatra 1.0
編集2:問題となっているコードは次のとおりです。これは Sinatra が JNLP を提供しているもので、ようやく判明しました。
get '/uploader' do
#read in the launch.jnlp file
theJNLP = ""
File.open("/launch.jnlp", "r+") do |file|
while theTemp = file.gets
theJNLP = theJNLP + theTemp
end
end
content_type :jnlp
theJNLP
end
これを Mongrel と http 経由で Sinatra で提供すると、すべて正常に動作します。これを https 経由で Sinatra と nginx で提供すると、上記のエラーが発生します。Web サイトのその他の部分はすべて同等のようです。
編集:それ以来、passenger 2.2.14、ruby 1.9.1、nginx 0.8.40、openssl 1.0.0a にアップグレードしましたが、変化はありません。
編集:原因は、SSL の使用による無限リダイレクトのようです。サーバーのルート ディレクトリに jnlp ファイルをホストする以外に、これを修正する方法はわかりません (一度に 1 つの jnlp ベースのアプリケーションに制限されるため、これは避けたいです)。
nginx.conf からの関連行:
# HTTPS server
#
server {
listen 443;
server_name MyServer.org
root /My/Root/Dir;
passenger_enabled on;
expires 1d;
proxy_set_header X-FORWARDED_PROTO https;
proxy_set_header X_FORWARDED_PROTO https;#the almighty google is not clear on which to use
location /upload {
proxy_pass https://127.0.0.1:443;
}
}
これに関して面白いのは、まず、jnlp を 'upload' ではなく 'uploader' というディレクトリに置いていたのですが、それでも proxy_pass ディレクティブがログに表示されたので、問題を引き起こしているように見えたことです。次に、jnlp をルートに移動すると、ssl によるプロキシがまったくなかったため、問題は回避されました。
では、nginx で無限 proxy_pass ループを回避するにはどうすればよいでしょうか?
答え1
nginx はポート 443 でリッスンしています。 へのリクエストを受け取ると/uploader
、ポート 443 にプロキシします。これが nginx です。別のポートでリッスンしている sinatra アプリにプロキシする必要があるようです。 nginx についてはよくわかりませんが、正しくないようです。