nginx + php-fpm - почему не работает POST-запрос?

2,084 views
Skip to first unread message

Gorynych

unread,
Jun 18, 2008, 3:16:22 AM6/18/08
to highload-php-ru
Здравствуйте!

Спасибо Андрею Нигматулину за быстрые ответы, но вопросы пока не
закончились :-)

Вопрос из серии "что я делаю не так?"

Есть связка nginx + php-fpm. GET-запрос к скрипту - проходит, POST -
не возвращается и рубится по таймауту.

Что интересно - по таймауту из php.ini, где стоит max_execution_time =
60;

Сам скрипт - простой тест, который пишет саме о себе лог.

f.php
====
<?php
$fp = null;
if ( ($fp=fopen("f.dump", "wb")) ) {
fwrite($fp, getenv("REQUEST_METHOD"));
if ( $_POST )
fwrite($fp, var_export($_POST, true));
}

echo "<html><body>";

echo "<form action=\"/test/f.php\" method=\"POST\">\n";
echo "<input type=\"text\" name=\"test\" value=\"\" />\n";
echo "<input type=\"submit\" />\n";
echo "</form>\n";

printf("<pre>%s</pre>", getenv("REQUEST_METHOD"));

echo "</body></html>";

if ( $fp ) {
fwrite($fp, " - PASS");
fclose($fp);
}
exit;
?>

При GET-запросе лог выглядит так:

GET - PASS

- что и ожидалось.

При POST-запросе гораздо интереснее:

POSTarray (
) - PASS

- т.е. запрос прошел, до записи в лог " - PASS" мы дошли, но... Массив
$_POST пуст, а скрипт завершается по таймауту из php.ini


Настройки:

nginx.conf
========

http {
client_header_timeout 3m;
client_body_timeout 3m;
send_timeout 3m;

client_header_buffer_size 1k;
large_client_header_buffers 4 4k;

access_log logs/access.log main; #main2
#buffer=32k;
proxy_read_timeout 120;
sendfile on;
tcp_nopush on;

#keepalive_timeout 0;
keepalive_timeout 65;
tcp_nodelay on;

gzip off;
#gzip_types application/x-javascript text/css text/plain text/html
image/bmp;
#gzip_comp_level 1;
#gzip_buffers 16 32k;

<- нашел в Сети утверждение, что проблема может быть из-за gzip -
временно отключил, но ничего не изменилось

...
server {
...
location ~ \.php$ {
# start fastcgi_pass with params:
fastcgi_pass_request_body off;
client_body_in_file_only clean;
fastcgi_pass unix:/tmp/test.sock;

# add fastcgi common params:
include fastcgi_params;

# add host's individual params:
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /guru2/www/mobiguru/
htdocs$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT /test/www/htdocs;
}
...

}

fastcgi_params
===========
fastcgi_param REQUEST_BODY_FILE $request_body_file;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param REQUEST_URI $request_uri;
#fastcgi_param DOCUMENT_URI $document_uri;

fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;

- вот тут интересно. Изначально я не включал REQUEST_BODY_FILE, потом
включил. Что характрно - в нем лежит то, что очень похоже на данные
POST-запроса.

Если собака зарыта тут, то в чем она?

php-fpm.conf
==========
...
<section name="global_options">
<value name="pid_file">/test/usr/php/logs/php-fpm.pid</
value>
<value name="error_log">/test/usr/php/logs/php-
fpm.log</value>
<value name="log_level">notice</value>
<value name="emergency_restart_threshold">10</value>
<value name="emergency_restart_interval">1m</value>
<value name="process_control_timeout">5s</value>
<value name="daemonize">yes</value>
</section>
<workers>
<section name="pool">
<value name="name">test</value>

<value name="listen_address">/tmp/test.sock</
value>
<value name="listen_options">
<value name="backlog">-1</value>
<value name="owner">test</value>
<value name="group">www</value>
<value name="mode">0660</value>
</value>
<value name="user">test</value>
<value name="group">www</value>

<value name="php_defines">
<value name="upload_tmp_dir">/test/www/
tmp</value>
<value name="open_basedir">/test/www/</
value>
<value name="session.save_path">/test/
www/tmp</value>
<value name="error_log">/test/www/tmp/
error.log</value>
</value>

<value name="pm">
<!-- <value name="style">static</
value> -->
<value name="style">apache-like</
value>
<value name="max_children">5</value>
<value name="apache_like">
<value name="StartServers">5</
value>
<value
name="MinSpareServers">1</value>
<value
name="MaxSpareServers">20</value>
</value>
</value>

<value name="request_execution_timeout">31s</
value>

<- судя по тому, что в access-логе время отдачи запросу около 60
секунд - эта настройка не работает или работает не правильно :-(

<value name="rlimit_files">1024</value>
<value name="rlimit_core">0</value>
<value name="chroot"></value>
<value name="chdir"></value>

<value name="catch_workers_output">yes</value>
<value name="max_requests">500</value>
<value name="allowed_clients">127.0.0.1</
value>

<value name="environment">
<value name="HOSTNAME">$HOSTNAME</
value>
<value name="PATH">/usr/local/bin:/usr/
bin:/bin</value>
<value name="TMP">/test/www/tmp</
value>
<value name="TMPDIR">/test/www/tmp</
value>
<value name="TEMP">/test/www/tmp</
value>
<value name="OSTYPE">$OSTYPE</value>
<value name="MACHTYPE">$MACHTYPE</
value>
<value name="MALLOC_CHECK_">2</value>
</value>
</section>
</workers>
</configuration>

Что я делаю не так? И как мне исправить ситуацию???

Andrei Nigmatulin

unread,
Jun 18, 2008, 6:33:29 AM6/18/08
to highloa...@googlegroups.com
On Wednesday 18 June 2008 11:16, Gorynych wrote:
> Есть связка nginx + php-fpm. GET-запрос к скрипту - проходит, POST -
> не возвращается и рубится по таймауту.
>
> <value name="user">test</value>
> <value name="group">www</value>

А nginx работает тоже с user/group = test/www ?


--
Andrei Nigmatulin
GPG PUB KEY 6449830D

Now I lay me down to sleep(3)
Pray the OS my core to keep
If I die before I wake
Pray the Disk my core to take

point

unread,
Jun 18, 2008, 9:50:18 AM6/18/08
to highload-php-ru
Попробую предположить: тело запроса складывается в файл (о чём нам
намекает директива client_body_in_file_only clean;), соотв-но в массив
$_POST оно не приходит.

Andrei Nigmatulin

unread,
Jun 18, 2008, 10:08:55 AM6/18/08
to highloa...@googlegroups.com

Тело запроса php должен читать сам, т.к. передается имя temp файла:

> fastcgi_param REQUEST_BODY_FILE $request_body_file;

Сдается мне что здесь проблема из-за того, что nginx ставит права на
client_temp файлы 700, а php работает из-под другого пользователя и тупо не
может их открыть.

То есть, две проблемы: nginx должен уметь выставлять что-то отличное от 700, а
php-fpm не должен зависать при ошибке открытия файла, а выдавать нормальную
ошибку.

Gorynych

unread,
Jun 19, 2008, 10:05:52 AM6/19/08
to highload-php-ru
Как и следовало ожидать - прав оказался Андрей :-)

Думаю, что кому-то еще это может пригодится, так что расскажу
(вкратце) что получилось и почему так.

Проблемы:

- nginx работает от пользователя www:www, а воркеры - от других
пользователей, входящих в эту же группу. Это делается специально, для
разделения доступа в каталоги отдельных проектов.

- nginx действительно создает временный файл с POST-запросом с правами
0700

Как я слышал около года назад от Сысоева - nginx не умеет и не будет
уметь запускать отдельные локейшены от разных пользователей, посему от
файлового способа передачи запроса пришлось отказаться.

- gzip успешно возвращен в nginz и на POST-запрос не влияет

т.е. имеем

fastcgi_pass_request_body on;
client_body_in_file_only off;

и возможность управлять доступом на уровне воркеров (фактически, на
рабочие каталоги разных воркеров у меня ставятся права 04710, что
позволяет запретить просмотр файлов "соседей").
On 18 июн, 18:08, Andrei Nigmatulin <andrei.nigmatu...@gmail.com>
wrote:

fixxxer

unread,
Jun 19, 2008, 10:23:20 AM6/19/08
to highload-php-ru
On Jun 19, 6:05 pm, Gorynych <dmitry.goryai...@gmail.com> wrote:
> - nginx действительно создает временный файл с POST-запросом с правами
> 0700
>
> Как я слышал около года назад от Сысоева - nginx не умеет и не будет
> уметь запускать отдельные локейшены от разных пользователей, посему от
> файлового способа передачи запроса пришлось отказаться.

~/nginx-0.6.31/src$ grep -R request_body_file_group_access *
http/ngx_http_request.h: unsigned
request_body_file_group_access:1;
http/modules/ngx_http_dav_module.c: r-
>request_body_file_group_access = 1;
http/ngx_http_request_body.c: if (r-
>request_body_file_group_access) {
http/ngx_http_request_body.c: if (r-
>request_body_file_group_access) {

http/ngx_http_request_body.c, ngx_int_t
ngx_http_read_client_request_body:

if (r->request_body_file_group_access) {
tf->access = 0660;
}

можно попросить Игоря добавить настройку
client_body_file_group_access, это, если я не ошибаюсь, всего
несколько строк. Или самостоятельно сделать такой патч :)
Reply all
Reply to author
Forward
0 new messages