Путь юниксоида

Блог посвященный UNIX-подобным операционным системам.

Настройка FastCGI (PHP FPM) для Nginx

11 Июня 2013, 18:54, Вт | Комментарии

Nginx to CentOS, Debian and Gentoo

FastCGI это высокопроизводительный и масштабируемый интерфейс для взаимодействия веб-сервера и приложений, дальнейшее развитие технологии CGI, однако CGI-скрипты перезапускаются с каждым запросом сервера, что существенно снижает производительность; FastCGI оставляет процессы запущенными и только передает им новые запросы.

nginx имеет собственную поддержку технологии FastCGI для работы с внешними серверами и утилитами. PHP тоже поддерживает FastCGI и может быть использован для обработки FastCGI-запросов от nginx.

В данном примере мы рассмотрим связку nginx и PHP-FPM. Для начала необходимо их установить, в большинстве дистрибутивах для установки есть пакеты с одноимёнными названиями. Или, например в Gentoo, для установки необходим USE флаг fpm, более подробно смотрите в документации к своему дистрибутиву.

Есть много руководств по настройке nginx для работы с PHP FPM, но многие из них являются неполными (неправильно обрабатывается переменная PATH_INFO) или содержат ошибки в обработке сценариев безопасности (отсутствует проверка наличия PHP кода в php файле).

Настроить подключение nginx и PHP-FPM можно двумя способами - либо через TCP‑порт (127.0.0.1:9000), либо unix сокет (/var/run/php-fpm.sock).

FastCGI параметры

Первая рекомендация - храните все типовые настройки FastCGI в отдельном файле и, при необходимости, импортируйте их.

Например для Debian и Ubuntu настройки по умолчанию находятся в файле /etc/nginx/fastcgi_params, который должен выглядеть следующим образом:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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   SCRIPT_FILENAME         $document_root$fastcgi_script_name;
fastcgi_param   SCRIPT_NAME             $fastcgi_script_name;
fastcgi_param   PATH_INFO               $fastcgi_path_info;
fastcgi_param   REQUEST_URI             $request_uri;
fastcgi_param   DOCUMENT_URI            $document_uri;
fastcgi_param   DOCUMENT_ROOT           $document_root;
fastcgi_param   SERVER_PROTOCOL         $server_protocol;
 
fastcgi_param   GATEWAY_INTERFACE       CGI/1.1;
fastcgi_param   SERVER_SOFTWARE         nginx/$nginx_version;
 
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;
 
fastcgi_param   HTTPS                   $https;
 
# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param   REDIRECT_STATUS         200;

Подключаем Nginx к PHP FPM

Тут мы должны сказать Nginx`у, чтобы проксировал запросы к PHP FPM через протокол FCGI:

1
2
3
4
5
6
7
8
9
10
location ~ [^/]\.php(/|$) {
    fastcgi_split_path_info ^(.+?\.php)(/.*)$;
    if (!-f $document_root$fastcgi_script_name) {
         return 404;
    }
 
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;
    include fastcgi_params;
}

В параметрах php-fpm.conf за подключение отвечает параметр listen.

1
2
3
4
# /etc/php/fpm-php5.X/php-fpm.conf
...
listen = 127.0.0.1:9000
...

В варианте подключения через unix сокет fastcgi_pass будет таким:

1
fastcgi_pass unix:/var/run/php5-fpm.sock;

А параметр listen вот так:

1
2
3
4
# /etc/php/fpm-php5.X/php-fpm.conf
...
listen = /var/run/php5-fpm.sock
...

После изменения настроек перезапустите nginx.

Тестирование

Создайте файл test.php в корневом каталоге nginx следующего содержания:

1
<?php var_export($_SERVER)?>

В браузере сделайте запрос:

1
2
3
4
5
/test.php
/test.php/
/test.php/foo
/test.php/foo/bar.php
/test.php/foo/bar.php?v=1

Обратите внимание на значение REQUEST_URI, SCRIPT_NAME, PATH_INFO и PHP_SELF.

Вот правильный вывод для

1
http://example.domain/test.php/foo/bar.php?v=1 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
array (
  'USER' => 'www-data',
  'HOME' => '/var/www',
  'FCGI_ROLE' => 'RESPONDER',
  'QUERY_STRING' => 'v=1',
  'REQUEST_METHOD' => 'GET',
  'CONTENT_TYPE' => '',
  'CONTENT_LENGTH' => '',
  'SCRIPT_FILENAME' => '/var/www/test.php',
  'SCRIPT_NAME' => '/test.php',
  'PATH_INFO' => '/foo/bar.php',
  'REQUEST_URI' => '/test.php/foo/bar.php?v=1',
  'DOCUMENT_URI' => '/test.php/foo/bar.php',
  'DOCUMENT_ROOT' => '/var/www',
  'SERVER_PROTOCOL' => 'HTTP/1.1',
  'GATEWAY_INTERFACE' => 'CGI/1.1',
  'SERVER_SOFTWARE' => 'nginx/1.4.0',
  'REMOTE_ADDR' => '192.168.56.1',
  'REMOTE_PORT' => '44644',
  'SERVER_ADDR' => '192.168.56.3',
  'SERVER_PORT' => '80',
  'SERVER_NAME' => '',
  'HTTPS' => '',
  'REDIRECT_STATUS' => '200',
  'HTTP_HOST' => 'lemp.test',
  'HTTP_USER_AGENT' => 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:20.0) Gecko/20100101 Firefox/20.0',
  'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  'HTTP_ACCEPT_LANGUAGE' => 'en-US,en;q=0.5',
  'HTTP_ACCEPT_ENCODING' => 'gzip, deflate',
  'HTTP_CONNECTION' => 'keep-alive',
  'PHP_SELF' => '/test.php/foo/bar.php',
  'REQUEST_TIME' => 1367829847,
)

Необходимые условия:
- Требования к PHP - версия 5.3.3 или выше.
- В php.ini значение cgi.fix_pathinfo = 1 (в некоторых мануалах советуют cgi.fix_pathinfo = 0 что может привести к не правильной обработке переменной PHP_SELF не равной DOCUMENT_URI).
- Регулярное выражение fastcgi_split_path_info должно корректно обрабатывать запросы, такие как /test.php/foo/blah.php или /test.php/.
- Необходимо разрешить nginx'у проверку *.php файлов чтобы предотвратить возможность передачи любых других файлов через PHP-FPM (например загруженные картинки).

Ознакомиться с более подробной информацией о FastCGI вы можете на официальном сайте.

Оригинал.

Комментарии