nginxをリバースプロキシにした時にPOSTがこける
問題
公開してるサーバにpukiwikiをインストールして外からアクセス出来るようにした。
が、新規ページを作成したりそのページ内容を更新したりはできるものの、
更新内容が多すぎるとInternalServerErrorがでる。
pukiwikiはphp製なので、「またPHPかよ…クソが…」とか思いながらエラーを見るも、phpからのエラーは一切出力されない…
解決
pukiwikiを入れてるwebサーバの前段にnginxでリバプロかましてたんだけど、このnginxが問題を起こしてた。
nginxのエラーログにはこんなのが出てた。
2012/06/30 23:40:19 [crit] 25289#0: *3164256 open() "/var/tmp/nginx/client//0000009328" failed (2: No such file or directory), client: 192.168.100.1, server: tatshimomura.info, request: "POST /xxx/ HTTP/1.1", host: "tatsh imomura.info", referrer: "http://tatshimomura.info/xxx/"
No such file or directoryってのはどういうことだ?
ただwikiのページ内容を更新するためにテキストをPOSTしてるだけなんだけど…
client_body_buffer_size
というディレクティブがnginxにはあって、こいつの設定がよくなかった。
Sets buffer size for reading client request body. In case request body is larger than the buffer, the whole body or only its part is written to a temporary file. By default, buffer size is equal to two memory pages. This is 8K on x86, other 32-bit platforms, and x86-64. It is usually 16K on other 64-bit platforms.
http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size
という感じで、
設定値よりも大きい容量のものがPOSTされると、その内容がtempfileに書き出されるらしい。
(多分書きだしたものをこのリバプロ背後にあるサーバに投げてるんだと思う…)
というわけでこのディレクティブをhttpのところに追加した。
client_body_buffer_size 50k;
これで問題なく更新できるようになった。めでたし。
client_body_temp_path
ではなんでNo such file or directoryというエラーと/var/tmp/nginx/client//0000009328という怪しげなパスがエラーログに出ていたのか。
多分client_body_temp_path pathというディレクティブの設定がうまくいってなかったのではないかと思う。
syntax: client_body_temp_path path [level1 [level2 [level3]]];
default:
client_body_temp_path client_body_temp;
context: http, server, location
Defines a directory for storing temporary files holding client request bodies. Up to three-level subdirectory hierarchy can be used underneath the specified directory. For example, in the following configurationclient_body_temp_path /spool/nginx/client_temp 1 2;
a temporary file might look like this:/spool/nginx/client_temp/7/45/00000123457
http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_temp_path
という感じでバッファサイズを超えたhttp request bodyは、このディレクティブで指定されるパスに一時ファイルとして保存される。
で、このディレクティブはなんか階層を指定できるみたいなので、その階層指定がうまくいってなかったためにエラーログに出てたようなスラッシュが2つ続きなパスを参照しようとしてしまったんじゃなかろうか。
さっきから「思う」とか「なかろうか」とかって言ってるのは未検証のため。デフォルトの設定はどうなってるかなどの情報が無いためよくわからん…
とりあえずは上の以下のようにしてもclient_body_buffer_sizeを変えずに問題なくPOSTができることが確認できた。ついでに一時ファイルが生成されてるのも確認できた。
client_body_temp_path /var/tmp/nginx;