Установка и настройка связки nginx и php-fpm

Опубликовано nekit - чт, 14/10/2021 - 22:15

Nginx в силу своей архитектуры быстро обрабатывает запросы и отдает статичные данные, в результате чего проект завоевал свою нишу на рынке, вытеснив такого мамонта, как Apache HTTP Server. Наличие в nginx поддержки интерфейсов (CGI, FastCGI и т.п.) позволило использовать его в связке с внешними приложениями, например, PHP, Perl, Python и другими. Описываемый в статье механизм не является новым и используется на высоконагруженных серверах уже давно. Статья написана в качестве заметки для себя и опубликована лишь только с той целью, что материал может оказаться полезным другим.

Итак, nginx является HTTP-сервером, а также умеет проксировать протоколы TCP, UDP, IMAP, POP3, HTTP и другие. Насколько мне известно, при написании nginx были использованы принципы событийно-ориентированного программирования, что и позволило добиться быстрой и эффективной обработки запросов с минимальными затратами ресурсов.

Ранее применение nginx было оправдано прежде всего для статических веб-сайтов. Однако с популяризацией данного продукта во многих приложениях появились возможности для привязки nginx без дополнительных ухищрений. Так, в PHP с версии 5.3.3 включен менеджер процессов FastCGI (PHP-FPM), который управляет ресурсами, а также созданием и уничтожением процессов PHP. Таким образом, появилась возможность из коробки использовать nginx в связке с PHP без включения в цепочку Apache HTTP Server с mod_php. Из недостатков данной связки следует отметить отсутствие в nginx аналогичного .htaccess в Apache механизма, который поддерживается практическими всеми веб-приложениями и позволяет гибко переносить их конфигурацию. Из-за этого, настройка веб-сервера осуществляется только в конфигурационном файле nginx, а директивы, указанные в .htaccess, приходится переводить в указанный конфиг. Опять же, нет худа без добра, отказ от данного механизма положительно сказывается на производительности, в результате снижения количества запросов к носителю информации (в конце статьи есть ссылка на заметку с комментариями разработчиков по этому поводу).

В портах FreeBSD доступно три вариации nginx: lite, full и обычная, которые различаются набором компилируемых модулей. Я ставлю обычную версию со своим набором опций и из своего репозитория. Также устанавливаем PHP с включенной опцией FPM (в официальном репозитории пакетов она включена).

  1. pkg install nginx php74

Далее, немного расскажу о иерархии директорий сайтов у меня на сервере. У каждого пользователя домашней директорией является /home/username/data с правами 0750, в которой есть следующие поддиректории: logs, www, tmp. В директории www хранятся сайты, logs   логи виртуальных хостов, а в tmp временные файлы PHP. Чтобы nginx мог получить к этим директориям доступ нужно добавить пользователя www в группу пользователя или можно воспользоваться ACL,ками, как сделал я:

  1. cd /home/h8/data
  2. mkdir logs tmp www
  3.  
  4. chown www:www logs
  5. chown h8:h8 tmp www
  6. chmod 0755 logs
  7. chmod 0750 tmp
  8. chmod 0751 www
  9.  
  10. setfacl -m u:www:x /home/h8
  11. setfacl -m u:www:x /home/h8/data
  12. setfacl -m u::rwx,g::rx,o::---,u:www:rx /home/h8/data/www
  13. setfacl -d -m u::rwx,g::rx,o::---,u:www:rx /home/h8/data/www

PHP-FPM будет порождать процессы PHP от конкретного пользователя, поэтому дополнительная настройка прав тут не требуется. Настройка PHP-FPM осуществляется посредством конфигурационного файла /usr/local/etc/php-fpm.conf, пулы PHP процессов настраиваются в отдельных конфигурационных файлах, размещаемых в /usr/local/etc/php-fpm.d. У меня настройки заданы следующим образом:

  1. ;;;;;;;;;;;;;;;;;;;;;
  2. ; Конфигурация FPM  ;
  3. ;;;;;;;;;;;;;;;;;;;;;
  4.  
  5. ; Конфигурационный файл заполняется в формате INI файла.
  6. ; Все относительные пути задаются относительно директории установки PHP (/usr/local).
  7. ; Данный префикс может быть изменен через параметр командной строки -p.
  8.  
  9. ;;;;;;;;;;;;;;;;;;;;;;;;
  10. ; Глобальные параметры ;
  11. ;;;;;;;;;;;;;;;;;;;;;;;;
  12.  
  13. [global]
  14. ; файл с идентификатором Pid
  15. ; Учтите: для данного параметра префикс: /var
  16. ; Значение по умолчанию: none
  17. pid = run/php-fpm.pid
  18.  
  19. ; Файл для записи ошибок
  20. ;  Если задано как "syslog", то логи будут направляться в syslogd, а не в локальный файл.
  21. ; Учтите: для данного параметра префикс: /var
  22. ; Значение по умолчанию: log/php-fpm.log
  23. error_log = log/php-fpm.log
  24.  
  25. ; Используется для указания, какой тип программ будет логировать сообщения.
  26. ; Смотрите ман syslog(3) для получения информации о доступных значениях.
  27. ; Значение по умолчанию: daemon
  28. ;syslog.facility = daemon
  29.  
  30. ; Предшествует любому сообщению. Если у вас запущено несколько экземпляры FPM,
  31. ; вы можете изменить значение по умолчанию на то, которое вам необходимо.
  32. ; Значение по умолчанию: php-fpm
  33. ;syslog.ident = php-fpm
  34.  
  35. ; Уровень журналирования ошибок.
  36. ; Возможные значения: alert, error, warning, notice, debug
  37. ; Значение по умолчанию: notice
  38. log_level = warning
  39.  
  40. ; Максимальное количество символов в строке.
  41. ; Если в сообщении будет превышен лимит символов, тогда оно будет разбито
  42. ; на несколько сообщений. Также учитываются символы, которые подставляются
  43. ; из prefix и suffix. However, the new line character does not count into it as it is present
  44. ; only when logging to a file descriptor. It means the new line character is not present
  45. ; when logging to syslog.
  46. ; Значение по умолчанию: 1024
  47. log_limit = 4096
  48.  
  49. ; Переменная управляет поведением записи данных в файл.
  50. ; Если значение установлено в false , тогда данные записываются незамедлительно.
  51. ; Данный механизм является экспериментальным и разработан для
  52. ; сокращения количества записей на диск и потребляемой памяти.
  53. ; Опция игнорируется, если лог ведется в syslog.
  54. ; Значение по умолчанию: yes
  55. log_buffering = yes
  56.  
  57. ; При указанном здесь количестве рабочих процессов, завершённых с SIGSEGV
  58. ; или SIGBUS за промежуток времени, установленный emergency_restart_interval,
  59. ; FPM будет перезагружен. Если параметр щадан в 0, тогда данный функционал
  60. ; не применяется.
  61. ; Значение по умолчанию: 0
  62. ;emergency_restart_threshold = 0
  63.  
  64. ; Интервал времени, используемый emergency_restart_interval, чтобы определить,
  65. ; когда FPM будет перезагружен. Это может быть необходимо для избежания случайных
  66. ; повреждений в общей памяти ускорителя (accelerator). Доступные единицы измерения:
  67. ;  s (секунды), m (минуты), h (часы), или d (дни).
  68. ; Единица измерения по умолчанию: секунды.
  69. ; Значение по умолчанию: 0 (Выключено).
  70. ;emergency_restart_interval = 0
  71.  
  72. ; Время, в течение которого дочерние процессы ожидают ответа на сигналы,
  73. ; направленные  мастер-процесса.  Доступные единицы измерения:
  74. ; s (секунды), m (минуты), h (часы) или d (дни).
  75. ; Единица ; измерения по умолчанию: секунды.
  76. ; Значение по умолчанию: 0.
  77. process_control_timeout = 120s
  78.  
  79. ; Максимальное количество процессов, которое может создать FPM.
  80. ; Опция необходима, чтобы контролировать общее количество порожденных процессов.
  81. ; Используйте с осторожностью, с учетом имеющихся ресурсов сервера.
  82. ; Учтите: если установлено в "0", значит ограничение отсутствует.
  83. ; Значение по умолчанию: 0
  84. process.max = 512
  85.  
  86. ; Приоритет (Unix nice(2)) мастер-процесса (только если установлено).
  87. ; Допустимые значения от -19 (максимальный приоритет) до 20 (минимальный).
  88. ; Учтите: будет работать, если мастер-процесс запускается под root. В данном случае
  89. ; дочерние процессы будут наследовать приоритет мастер-процесса.
  90. ; Значение по умолчанию: no set
  91. process.priority = 19
  92.  
  93. ; Запускать FPM в фоновом режиме. Если установлено в "no",
  94. ; то FPM запустится в режиме отладки.
  95. ; Значение по умолчанию: yes
  96. daemonize = yes
  97.  
  98. ; Максимальное разрешенное количество одновременно открытых дескрипторов
  99. ; файлов для мастер-процесса.
  100. ; Значение по умолчанию: взятое с системы
  101. ;rlimit_files = 1024
  102.  
  103. ; Максимальный размер корки для мастер-процесса.
  104. ; Доступные значения: 'unlimited' или целочисленное значения большее либо равное 0
  105. ; Значение по умолчанию: взятое с системы
  106. ;rlimit_core = 0
  107.  
  108. ; Механизм обработки событий. Доступные значения ( в зависимости от ОС):
  109. ; - select     (any POSIX os)
  110. ; - poll       (any POSIX os)
  111. ; - epoll      (linux >= 2.5.44)
  112. ; - kqueue     (FreeBSD >= 4.1, OpenBSD >= 2.9, NetBSD >= 2.0)
  113. ; - /dev/poll  (Solaris >= 7)
  114. ; - port       (Solaris >= 10)
  115. ; Значение по умолчанию: not set (auto detection)
  116. events.mechanism = kqueue
  117.  
  118. ; Если FPM собран с поддержкой systemd, тогда здесь возможно
  119. ; указать интервал времени в секундах, между оповещениями systemd
  120. ; о своём состоянии.
  121. ; Установите в 0, чтобы отключить.
  122. ; Доступные единицы измерения: s (секунды), m (минуты), h (часы).
  123. ; Единица ; измерения по умолчанию: секунды
  124. ; Значение по умолчанию: 10
  125. ;systemd_interval = 10
  126.  
  127. ;;;;;;;;;;;;;;;;;;;;
  128. ; Pool Definitions ;
  129. ;;;;;;;;;;;;;;;;;;;;
  130.  
  131. ; Каждый пул процессов может быть запущен на своем IP и порту (либо unix сокете)
  132. ; с различными параметрами выполнения. Имя пула должно быть уникальным
  133. ; и будет использоваться в логах и статистике. Количество пулов неограниченно.
  134. ;  Your system will tell you anyway :)
  135.  
  136. ; Подключите  один или несколько файлов.
  137. ; Include one or more files. If glob(3) exists, it is used to include a bunch of
  138. ; files from a glob(3) pattern. This directive can be used everywhere in the file.
  139. ; Допустимо использовать относительные пути. Префикс может быть таким:
  140. ;  - глобальный префикс, заданный через параметр -p
  141. ;  - либо /usr/local
  142. include=/usr/local/etc/php-fpm.d/*.conf

Пример настройки пула /usr/local/etc/php-fpm.d/h8.conf:

  1. ; Объявляем новый пул с именем 'h8'.
  2. ; Переменная $pool может быть использована в любой директиве и будет заменена
  3. ; на имя пула, в данном случае на "h8".
  4. [h8]
  5. ; Префикс для пула. Используется только в следующих параметрах:
  6. ; - 'access.log'
  7. ; - 'slowlog'
  8. ; - 'listen' (unixsocket)
  9. ; - 'chroot'
  10. ; - 'chdir'
  11. ; - 'php_values'
  12. ; - 'php_admin_values'
  13. ; В случае если префикс не задан, используется глобальный (или /usr/local).
  14. ; Учтите: значение директивы может быть относительным глобального префикса.
  15. ; Значение по умолчанию: none
  16. prefix = /home/$pool/data
  17.  
  18. ; Имя и группа, под которыми будет работать процессы в пуле.
  19. ; Учтите: указание директивы user обязательно. Если директива group не задана,
  20. ; тогда будет использована основная группа пользователя, указанного в user.
  21. user = h8
  22. group = h8
  23.  
  24. ; Адрес, на котором пул процессов будет принимать запросы.
  25. ; Допустимые значения:
  26. ;   'ip.add.re.ss:port'    - прием посредством TCP на конкретных IPv4 и порту
  27. ;   '0.0.0.0:port'         - прием посредтсвом TCP на любом IPv4 и конкретном порту
  28. ;   '[ip:6:addr:ess]:port' - прием посредством TCP на конкретных IPv6 и порту
  29. ;   'port'                 - прием посредством TCP на любых (IPv6 and IPv4-mapped) и конкретном порту
  30. ;                            Учтите: IPv4-mapped addresses are disabled by-default in
  31. ;                                  FreeBSD for security reasons;
  32. ;   '/path/to/unix/socket' - прием посредством unix-сокета.
  33. ; Учтите: значение указывается в обязательном порядке.
  34. listen = /var/run/h8.sock
  35.  
  36. ; В случае использования unix-сокета указываем права доступа к нему. В Linux, права
  37. ; read/write должны быть установлены таким образом, чтобы мог подключиться веб-сервер.
  38. ; Некоторые BSD системы допускают подключение независимо от прав доступа. Владелец
  39. ; сокета может быть указан по имени name либо ID.
  40. ; Значение по уполчанию: user и group мастер-процесса и права доступа 0660
  41. listen.owner = h8
  42. listen.group = www
  43. listen.mode = 0660
  44.  
  45. ; В случае наличия поддержки POSIX Access Control Lists возможно задать
  46. ; через запятую user/group. Если этот параметр задан, тогда listen.owner
  47. ; и listen.group игнорируются.
  48. ;listen.acl_users =
  49. ;listen.acl_groups =
  50.  
  51. ; Приоритет (Unix nice(2)) для процессов в пуле. Допустимые значения
  52. ; от -19 (максимальный приоритет) до 20 (минимальный).
  53. ; Учтите: будет работать, если мастер-процесс запускается под root. В данном случае
  54. ; дочерние процессы будут наследовать приоритет мастер-процесса, если параметр не задан.
  55. ; Значение по умолчанию: no set
  56. process.priority = 19
  57.  
  58. ; Установить флаг процесса dumpable (PR_SET_DUMPABLE prctl), даже если пользователь
  59. ; процесса или группа отличается от пользователя мастер-процесса. Указанное позволяет
  60. ; создавать дамп памяти процесса и выполнить его ptrace.
  61. ; Значение по умолчанию: no.
  62. process.dumpable = no
  63.  
  64. ; Здесь задается способ порождения процессов.
  65. ; Допустимые значения:
  66. ;   static  - фиксированное число дочерних процессов (pm.max_children)
  67. ;   dynamic - переменное число дочерних процессов, задаётся на основании следующих директив.
  68. ;             (With this process management, there will be always at least 1 children)
  69. ;             pm.max_children
  70. ;             pm.start_servers
  71. ;             pm.min_spare_servers
  72. ;             pm.max_spare_servers
  73. ;  ondemand - дочерние процессы создаются только по требованию, задаётся
  74. ;             на основании следующих директив:
  75. ;             pm.max_children
  76. ;             pm.process_idle_timeout
  77. ; Учтите: задание параметра является обязательным.
  78. pm = dynamic
  79.  
  80. ; Количество процессов, создаваемых в режиме "static", а в случае режимов
  81. ; "dynamic" или "ondemand" :nbsp; максимальное количество процессов,
  82. ; работающих одновременно. Фактически данный параметр ограничивает
  83. ; количество одновременно обрабатываемых запросов.
  84. ; Действие параметра аналогично директиве ApacheMaxClients сервера Apache
  85. ; с MPM модудем mpm_prefork и аналогично переменной окружения PHP_FCGI_CHILDREN
  86. ; в оригинальном PHP CGI. Значение по умолчанию выбрано без учета мощности оборудования.
  87. ; Необходимо настраивать параметры pm.* под свои нужды.
  88. ; Учтите: указание значения обязательно.
  89. pm.max_children = 7
  90.  
  91. ; Количество процессов в пуле, создаваемых на этапе запуска.
  92. ; Учтите: оказывает влияние только в режиме 'dynamic'.
  93. ; Значение по умолчанию: (min_spare_servers + max_spare_servers) / 2
  94. ; pm.start_servers = 1
  95.  
  96. ; Минимальное количество неактивных (простаивающих) процессов пула.
  97. ; Используется только, когда pm установлено в "dynamic".
  98. ; Учтите: указание значения обязательно.
  99. pm.min_spare_servers = 1
  100.  
  101. ; Макималное количество неактивных (простаивающих) процессов пула.
  102. ; Используется только, когда pm установлено в "dynamic".
  103. ; Учтите: указание значения обязательно.
  104. pm.max_spare_servers = 5
  105.  
  106. ; Время в секундах, по истечению которого неактивный (простаивающий)
  107. ; процесс будет уничтожен.
  108. ; Используется только, когда pm установлено в "ondemand".
  109. ; Значение по уполчанию: 10s
  110. ;pm.process_idle_timeout = 10s;
  111.  
  112. ; Количество обработанных каждым процессом из пула запросов, после
  113. ; которого процесс будет уничтожен и создан заного. Данный функционал может
  114. ; быть полезен для профилактики утечки памяти в случае наличия багов в сторонних
  115. ; библиотеках. Отключение функции осуществляется установкой параметра в 0.
  116. ; По своей сути функционал аналогичен PHP_FCGI_MAX_REQUESTS.
  117. ; Значение по умолчанию: 0
  118. pm.max_requests = 1000
  119.  
  120. ; Путь до файла, в который будут записываться данные об обработанных запросах (лог доступа).
  121. ; Значение по умолчанию: not set
  122. ;access.log = log/$pool.access.log
  123.  
  124. ; Формат записей в лог доступа.
  125. ; Допустим следующий синтаксис:
  126. ;  %%: the '%' character
  127. ;  %C: %CPU used by the request
  128. ;      it can accept the following format:
  129. ;      - %{user}C for user CPU only
  130. ;      - %{system}C for system CPU only
  131. ;      - %{total}C  for user + system CPU (default)
  132. ;  %d: time taken to serve the request
  133. ;      it can accept the following format:
  134. ;      - %{seconds}d (default)
  135. ;      - %{miliseconds}d
  136. ;      - %{mili}d
  137. ;      - %{microseconds}d
  138. ;      - %{micro}d
  139. ;  %e: an environment variable (same as $_ENV or $_SERVER)
  140. ;      it must be associated with embraces to specify the name of the env
  141. ;      variable. Some exemples:
  142. ;      - server specifics like: %{REQUEST_METHOD}e or %{SERVER_PROTOCOL}e
  143. ;      - HTTP headers like: %{HTTP_HOST}e or %{HTTP_USER_AGENT}e
  144. ;  %f: script filename
  145. ;  %l: content-length of the request (for POST request only)
  146. ;  %m: request method
  147. ;  %M: peak of memory allocated by PHP
  148. ;      it can accept the following format:
  149. ;      - %{bytes}M (default)
  150. ;      - %{kilobytes}M
  151. ;      - %{kilo}M
  152. ;      - %{megabytes}M
  153. ;      - %{mega}M
  154. ;  %n: pool name
  155. ;  %o: output header
  156. ;      it must be associated with embraces to specify the name of the header:
  157. ;      - %{Content-Type}o
  158. ;      - %{X-Powered-By}o
  159. ;      - %{Transfert-Encoding}o
  160. ;      - ....
  161. ;  %p: PID of the child that serviced the request
  162. ;  %P: PID of the parent of the child that serviced the request
  163. ;  %q: the query string
  164. ;  %Q: the '?' character if query string exists
  165. ;  %r: the request URI (without the query string, see %q and %Q)
  166. ;  %R: remote IP address
  167. ;  %s: status (response code)
  168. ;  %t: server time the request was received
  169. ;      it can accept a strftime(3) format:
  170. ;      %d/%b/%Y:%H:%M:%S %z (default)
  171. ;      The strftime(3) format must be encapsuled in a %{<strftime_format>}t tag
  172. ;      e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t
  173. ;  %T: time the log has been written (the request has finished)
  174. ;      it can accept a strftime(3) format:
  175. ;      %d/%b/%Y:%H:%M:%S %z (default)
  176. ;      The strftime(3) format must be encapsuled in a %{<strftime_format>}t tag
  177. ;      e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t
  178. ;  %u: remote user
  179. ;
  180. ; Значение по умолчанию: "%R - %u %t \"%m %r\" %s"
  181. ;access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%"
  182.  
  183. ; Путь до файла, в который будут записываться данные о медленных запросах.
  184. ; Значение по умолчанию: not set
  185. ; Учтите: задание параметра обязательно при указании параметра request_slowlog_timeout
  186. ;slowlog = log/$pool.log.slow
  187.  
  188. ; Время, после которого выполняемых запрос будет считаться медленным, в результате чего
  189. ; данные об этом будут записаны в файл 'slowlog'. Значение '0' отключает данный функционал.
  190. ; Доступные единицы измерения: s (секунды, по умолчанию), m (минуты), h (часы) или d (дни).
  191. ; Значение по умолчанию: 0
  192. ;request_slowlog_timeout = 0
  193.  
  194. ; Информативность (глубина) записей в slowlog.
  195. ; Значение по умолчанию: 20
  196. ;request_slowlog_trace_depth = 20
  197.  
  198. ; Максимальное время обработки запроса, при превышении которого
  199. ; процесс будет уничтожен. Данный параметр может оказаться полезным,
  200. ; в случае если PHP параметр 'max_execution_time' не сработает по какой-либо
  201. ; причине. Значение в 0 отключает данный функционал.
  202. ; Доступные единицы измерения: s (секунды, по умолчанию), m (минуты), h (часы) или d (дни).
  203. ; Значение по уполчанию: 0
  204. ;request_terminate_timeout = 0
  205.  
  206. ; The timeout set by 'request_terminate_timeout' ini option is not engaged after
  207. ; application calls 'fastcgi_finish_request' or when application has finished and
  208. ; shutdown functions are being called (registered via register_shutdown_function).
  209. ; This option will enable timeout limit to be applied unconditionally
  210. ; even in such cases.
  211. ; Default Value: no
  212. ;request_terminate_timeout_track_finished = no
  213.  
  214. ; Вы полнить chroot() в указанную здесь директорию после запуска процесса.
  215. ; Путь к директории должен быть полным (абсолютным). Если значение не задано,
  216. ; тогда chroot() не применяется.
  217. ; Учтите: возможно использовать пеерменную $prefix, указанную ранее для пула.
  218. ; Если префикс для пула не указывался, тогда будет использован глобальный префикс.
  219. ; Учтите: chroot является мощным интрументом безопасности и должен
  220. ; использоваться во всевозможных случаях. Однако следует учитывать,
  221. ; что все пути для PHP будут относительны указанной здесь директории
  222. ;       (error_log, sessions.save_path, ...).
  223. ; Значение по умолчанию: not set
  224. ;chroot =
  225.  
  226. ; Выполнить chdir в директорию после старта.
  227. ; Учтите: может быть указан относительный путь.
  228. ; Значение по уполчанию:  текущая директория или / при использовании chroot.
  229. ;chdir = /var/www
  230.  
  231. ; Перенаправление STDOUT и STDERR рабочего процесса в главный лог ошибок.
  232. ; Если не установлен, тогда вывод STDOUT и STDERR будет перенаправлен в /dev/null
  233. ;  в соответствии со спецификацией FastCGI.
  234. ; Note: on highloaded environement, this can cause some delay in the page
  235. ; process time (several ms).
  236. ; Значение по умолчанию: no.
  237. ;catch_workers_output = yes
  238.  
  239. ; Decorate worker output with prefix and suffix containing information about
  240. ; the child that writes to the log and if stdout or stderr is used as well as
  241. ; log level and time. This options is used only if catch_workers_output is yes.
  242. ; Settings to "no" will output data as written to the stdout or stderr.
  243. ; Default value: yes
  244. ;decorate_workers_output = no
  245.  
  246. ; Удалить переменные окружения для процессов из пула, таким образом
  247. ; предотвратив утечку чувствительных данных через указанные переменные
  248. ; Установка в "no" будет означать, что к информации из переменных окружения,
  249. ; действовавших на этапе создания процесса, можно будет получить доступ
  250. ; в скриптах через getenv(), $_ENV и $_SERVER.
  251. ; Значение по уполчанию: yes
  252. clear_env = yes
  253.  
  254. ; Здесь возможно указать расширения файлов, которые PHP-FPM
  255. ; будет воспринимать в качестве скриптов. Данный механизм
  256. ; поможет обезопасить сервер при наличии упущений в конфигурации
  257. ; веб-сервера (например, всем известная фишка с cgi.fix_path_info).
  258. ; Следует ограничить FPM обрабатывать файлы только с расширеним .php
  259. ; для исключения подстановки вредоносного когда через файлы
  260. ; с иными расширениями.
  261. ; Учтите: оставьте значение пустым, чтобы разрешить FPM выполнять любые файлы
  262. ; Значение по уполчанию: .php
  263. security.limit_extensions = .php .php3 .php4 .php5 .php7
  264.  
  265. ; Задать переменные окружения для скриптов.. Все $VARIABLEs будут
  266. ; взяты из исходного окружения.
  267. ; Значение по умолчанию: clean env
  268. ;env[HOSTNAME] = $HOSTNAME
  269. env[PATH] = /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/root/bin
  270. env[TMP] = /home/h8/data/tmp
  271. env[TMPDIR] = /home/h8/data/tmp
  272. env[TEMP] = /home/h8/data/tmp
  273.  
  274. ; Additional php.ini defines, specific to this pool of workers. These settings
  275. ; overwrite the values previously defined in the php.ini. The directives are the
  276. ; same as the PHP SAPI:
  277. ;   php_value/php_flag             - you can set classic ini defines which can
  278. ;                                    be overwritten from PHP call 'ini_set'.
  279. ;   php_admin_value/php_admin_flag - these directives won't be overwritten by
  280. ;                                     PHP call 'ini_set'
  281. ; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no.
  282.  
  283. ; Defining 'extension' will load the corresponding shared extension from
  284. ; extension_dir. Defining 'disable_functions' or 'disable_classes' will not
  285. ; overwrite previously defined php.ini values, but will append the new value
  286. ; instead.
  287.  
  288. ; Note: path INI options can be relative and will be expanded with the prefix
  289. ; (pool, global or /usr/local)
  290.  
  291. ; Default Value: nothing is defined by default except the values in php.ini and
  292. ;                specified at startup with the -d argument
  293.  
  294. php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f admin@example.ru
  295. php_value[error_reporting] = E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED
  296. php_flag[display_errors] = Off
  297. php_value[default_charset] = "UTF-8"
  298. php_flag[log_errors] = On
  299. php_admin_value[error_log] = /home/h8/data/logs/php-errors.log
  300. php_admin_value[max_input_time] = 120
  301. php_admin_value[max_execution_time] = 120
  302. php_admin_value[memory_limit] = 256M
  303. php_admin_value[upload_max_filesize] = 16M
  304. php_admin_value[post_max_size] = 32M
  305. php_value[date.timezone] = Europe/Moscow
  306. php_admin_value[open_basedir] = .:/home/h8/data/:/usr/local/share/pear/:/dev/urandom
  307. php_admin_value[upload_tmp_dir] = /home/h8/data/tmp
  308. php_admin_value[session.save_path] = /home/h8/data/tmp
  309. php_admin_flag[session.bug_compat_42] = Off
  310. php_admin_flag[session.bug_compat_warn] = Off
  311. php_admin_value[session.gc_divisor] = 1000
  312. php_admin_value[session.hash_bits_per_character] = 5
  313. php_admin_flag[expose_php] = Off
  314. php_admin_value[variables_order] = GPCS
  315. php_admin_value[request_order] = GP
  316. php_admin_flag[register_argc_argv] = Off
  317. php_admin_value[auto_globals_jit] = On
  318.  
  319. ; Drupal config from .htaccess
  320. php_admin_value[assert.active] = 0
  321. php_admin_flag[session.auto_start] = off
  322. php_admin_value[mbstring.http_input] = pass
  323. php_admin_value[mbstring.http_output] = pass
  324. php_admin_flag[mbstring.encoding_translation] = off
  325. ; PHP 5.6 has deprecated $HTTP_RAW_POST_DATA and produces warnings
  326. ; if this is not set.
  327. php_admin_value[always_populate_raw_post_data] = -1
  328.  
  329. php_admin_value[opcache.enable] = 1
  330. php_admin_value[opcache.memory_consumption] = 128
  331. php_admin_value[opcache.interned_strings_buffer] = 16
  332. php_admin_value[opcache.max_accelerated_files] = 8000
  333. php_admin_value[opcache.revalidate_freq] = 60
  334. php_admin_value[opcache.save_comments] = 1
  335. php_admin_value[opcache.fast_shutdown] = 1
  336. php_admin_value[opcache.enable_cli] = 1
  337.  
  338. php_admin_value[apc.enabled] = 0
  339.  
  340. php_flag[verify_peer] = off
  341. php_flag[verify_peer_name] = off

Стоит отметить одну особенность работы PHP-FPM, а именно невозможность загрузки различных модулей расширения PHP для пулов. То есть модули расширения загружаются однократно мастер-процессом и далее видны всем дочерним процессам. Если в какой-то ситуации необходимо создать пулы с различным набором подгруженных модулей , тогда целесообразно запускать несколько мастер-процессов с разной конфигурацией. Другим более простым вариантом является отключение функционала модулей через php_admin_value.

Итак, после настройки конфигов для PHP-FPM стоит попробовать его запустить, для чего делаем следующее:

  1. echo 'php_fpm_enable="YES"' >> /etc/rc.conf
  2. service php-fpm start
  3. ps -ax | grep php
  4.  5302  -  INJ  7:01,56 php-fpm: pool h8 (php-fpm)
  5.  5303  -  INJ  7:07,16 php-fpm: pool h8 (php-fpm)
  6. 18592  -  INJ  0:35,04 php-fpm: pool h8 (php-fpm)
  7. 25324  -  INJ  0:20,32 php-fpm: pool h8 (php-fpm)
  8. 29026  -  INJ  5:26,86 php-fpm: pool h8 (php-fpm)
  9. 65536  -  SNsJ 0:06,70 php-fpm: master process (/usr/local/etc/php-fpm.conf) (php-fpm)

Если при запуске PHP-FPM не выкинул никаких ошибок, тогда его настройку можно считать завершенной. Теперь давайте настроим nginx, его основной конфигурационный файл находится тут /usr/local/etc/nginx/nginx.conf. Далее, приведу содержимое указанного файла с комментариями по ходу следования параметров:

  1. # Задаём пользователя и группу, с правами которого будут работать рабочие процессы.
  2. # Если группа не задана, то используется группа, имя которой совпадает с именем пользователя.
  3. user  www;
  4. # Задаёт число рабочих процессов. Оптимально значение равное количеству ядер в системе.
  5. # Также возможно указать значение auto.
  6.  
  7. # У меня nginx скомпилирован с модулем GeoIP2, поэтому я его тут подгружаю
  8. load_module /usr/local/libexec/nginx/ngx_http_geoip2_module.so;
  9.  
  10. # This default error log path is compiled-in to make sure configuration parsing
  11. # errors are logged somewhere, especially during unattended boot when stderr
  12. # isn't normally logged anywhere. This path will be touched on every nginx
  13. # start regardless of error log location configured here. See
  14. # https://trac.nginx.org/nginx/ticket/147 for more info.
  15. #
  16. error_log  /var/log/nginx/error.log;
  17.  
  18.   # Задаёт метод, используемый для обработки соединений (если не указан,
  19.   # то nginx сам выбирает наиболее эффективный метод).
  20.   use kqueue;
  21.   # Задаёт максимальное число соединений, которые одновременно может открыть рабочий процесс.
  22. }
  23.  
  24.   # Разрешает или запрещает выдавать версию nginx’а на страницах ошибок
  25.   # и в поле “Server” заголовка ответа.
  26.  
  27.   include       mime.types; # Подключаем файлик со сведениями о MIME.
  28.   default_type  application/octet-stream; # все файлы с неизвестным MIME будем трактовать как бинарник
  29.  
  30.   # На официальном сайте к nginx есть описание всех доступных переменных
  31.   log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
  32.               '$status $body_bytes_sent "$http_referer" '
  33.               '"$http_user_agent" "$http_x_forwarded_for"';
  34.  
  35.   # Параметры SSL
  36.   # Время, в течение которого nginx будет хранить параметры SSL сессии клиента
  37.   # Кэшируем SSL сесси для того чтобы сократить количество рукопожатий SSL с клиентами,
  38.   # таким образом снижая нагрузку на процессор.Тип и размеры кэшей для хранения
  39.   # параметров SSL сессий (20m ~ 80000 сессий)
  40.   ssl_session_cache shared:nginxSSL:20m;
  41.   ssl_session_tickets off; # Запрещаем возобновление сессий при помощи TLS session tickets.
  42.   ssl_prefer_server_ciphers off; # В данном случае клиентские шифры более приоритетны, чем серверные.
  43.  
  44.   # Данные параметры получены в генераторе от Mozilla (в конце статьи  есть ссылка)
  45.   ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  46.   ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
  47.   ssl_dhparam dhparam.pem; # создан командой: openssl dhparam -out dhparam.pem 2048
  48.  
  49.   sendfile        on;
  50.   #tcp_nopush     on;
  51.  
  52.   # TCP options
  53.   # Ничего особенного, подбираются индивидуально
  54.   keepalive_time 5m;
  55.  
  56.   # GeoIP options
  57.   geoip2 /usr/local/share/GeoIP/GeoLite2-Country.mmdb {
  58.     auto_reload 1d; # через какой время nginx будт перезагружать базу
  59.  
  60.     # $variable_name metadata <field>
  61.     # Доступные значения:
  62.     #   build_epoch: время создания ьазы данных maxmind.
  63.     #   last_check: время, когда  база последний раз была проверена на предмет изменений (when using auto_reload)
  64.     #   last_change: время, когда  база последний раз была перезагружена (when using auto_reload)
  65.  
  66.     #$geoip2_metadata_country_build metadata build_epoch;
  67.  
  68.     # $variable_name [default=<value] [source=$variable_with_ip] path ...
  69.     # Структуру базы можно подглядеть так:  mmdblookup --file /path/to/GeoLite2-Country.mmdb --ip 127.0.0.1
  70.     $geoip2_data_continent_code continent code;
  71.     $geoip2_data_country_code country iso_code;
  72.     $geoip2_data_country_name country names en;
  73.   }
  74.  
  75.   geoip2 /usr/local/share/GeoIP/GeoLite2-City.mmdb {
  76.     auto_reload 1d;
  77.     $geoip2_data_city_name city names en;
  78.     $geoip2_data_region subdivisions 0 names en;
  79.     $geoip2_data_location_latitude location latitude;
  80.     $geoip2_data_location_longitude location longitude;
  81.   }
  82.  
  83.   # Все виртуальные хосты у меня описаны в конфигурационных файлах в этой поддиректории
  84.   include vhosts/*.conf;
  85. }

В директории /usr/local/etc/nginx имеется файл fastcgi_params, в котором задаются переменные окружения, передаваемые клиенту. Я его немного подредактировал с учетом наличия модуля GeoIP2, а также убрал вывод версии nginx и добавил переменную SCRIPT_FILENAME.

  1. fastcgi_param  QUERY_STRING       $query_string;
  2. fastcgi_param  REQUEST_METHOD     $request_method;
  3. fastcgi_param  CONTENT_TYPE       $content_type;
  4. fastcgi_param  CONTENT_LENGTH     $content_length;
  5.  
  6. fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
  7. fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
  8. fastcgi_param  PATH_INFO          $fastcgi_path_info;
  9. fastcgi_param  PATH_TRANSLATED    $document_root$fastcgi_path_info;
  10. fastcgi_param  REQUEST_URI        $request_uri;
  11. fastcgi_param  DOCUMENT_URI       $document_uri;
  12. fastcgi_param  DOCUMENT_ROOT      $document_root;
  13. fastcgi_param  SERVER_PROTOCOL    $server_protocol;
  14. fastcgi_param  REQUEST_SCHEME     $scheme;
  15. fastcgi_param  HTTPS              $https if_not_empty;
  16.  
  17. fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
  18. fastcgi_param  SERVER_SOFTWARE    nginx;
  19.  
  20. fastcgi_param  REMOTE_ADDR        $remote_addr;
  21. fastcgi_param  REMOTE_PORT        $remote_port;
  22. fastcgi_param  SERVER_ADDR        $server_addr;
  23. fastcgi_param  SERVER_PORT        $server_port;
  24. fastcgi_param  SERVER_NAME        $server_name;
  25.  
  26. # PHP only, required if PHP was built with --enable-force-cgi-redirect
  27. fastcgi_param  REDIRECT_STATUS    200;
  28.  
  29. # GeoIP
  30. fastcgi_param  COUNTRY_CODE       $geoip2_data_country_code;
  31. fastcgi_param  COUNTRY_NAME       $geoip2_data_country_name;
  32. fastcgi_param  CITY_NAME          $geoip2_data_city_name;
  33. fastcgi_param  REGION_NAME        $geoip2_data_region;
  34. fastcgi_param  LOCATION_LATITUDE  $geoip2_data_location_latitude;
  35. fastcgi_param  LOCATION_LONGITUDE $geoip2_data_location_longitude;

Ну и теперь настраиваем виртуальный хост:

  1.   listen       80;
  2.   server_name  example.org;
  3.   index index.php;
  4.   root /home/h8/data/www/example.org; # директория, содержащая веб-приложение
  5.   charset utf-8; # кодировка по умолчанию
  6.   autoindex off; # запрещаем вывод списка каталогов.
  7.  
  8.   # Пути до лог файлов
  9.   error_log   /home/h8/data/logs/example.org.error.log;
  10.   access_log  /home/h8/data/logs/example.org.access.log  main;
  11.  
  12.   # HTTP response headers borrowed from Drupal `.htaccess`
  13.   add_header X-Content-Type-Options               "nosniff"       always;
  14.  
  15.   # Включаем сжатие gzip ( but do not remove ETag headers)
  16.   gzip on;
  17.   gzip_vary on;
  18.   gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
  19.   gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
  20.  
  21.   location = /robots.txt {
  22.     allow all;
  23.     log_not_found off;
  24.     access_log off;
  25.   }
  26.  
  27.   location = /favicon.ico {
  28.     log_not_found off;
  29.     access_log off;
  30.   }
  31.  
  32.   location ~ \..*/.*\.php$                     { return 403; }
  33.   location ~ ^/sites/.*/private/               { return 403; }
  34.   # Block access to scripts in "site" "files" directory
  35.   location ~ ^/sites/[^/]+/files/.*\.php$      { deny all; }
  36.   # Allow "Well-Known URIs" as per RFC 5785
  37.   location ~* ^/.well-known/                   { allow all; }
  38.   # Deny access to .htaccess files, if Apache's document root
  39.   # concurs with nginx's one
  40.   location ~ /\.ht { deny  all; }
  41.  
  42.   location / {
  43.     # try_files $uri @rewrite; # For Drupal <= 6
  44.     try_files $uri /index.php?$query_string; # For Drupal >= 7
  45.   }
  46.  
  47.   # Block access to "hidden" files and directories whose names begin with a
  48.   # period. This includes directories used by version control systems such
  49.   # as Subversion or Git to store control files.
  50.   location ~ (^|/)\.                           { return 403; }
  51.  
  52.   # Don't allow direct access to PHP files in the vendor directory.
  53.   location ~ /vendor/.*\.php$ {
  54.     deny all;
  55.     return 404;
  56.   }
  57.  
  58.   # Protect files and directories from prying eyes.
  59.   location ~* \.(engine|inc|install|make|module|profile|po|sh|.*sql|theme|twig|tpl(\.php)?|xtmpl|yml)(~|\.sw[op]|\.bak|\.orig|\.save)?$|^(\.(?!well-known).*|Entries.*|Repository|Root|Tag|Template|composer\.(json|lock)|web\.config)$|^#.*#$|\.php(~|\.sw[op]|\.bak|\.orig|\.save)$ {
  60.     deny all;
  61.     return 404;
  62.   }
  63.  
  64.     #rewrite ^/(.*)$ /index.php?q=$1; # For Drupal <= 6
  65.     rewrite ^ /index.php; # For Drupal >= 7
  66.   }
  67.  
  68.   # Workaround Drupal bug #2583799 - https://www.drupal.org/node/2583799
  69.   rewrite ^/core/authorize.php/core/authorize.php(.*) /core/authorize.php?$1 permanent;
  70.  
  71.   # In Drupal 8, we must also match new paths where the '.php' appears in
  72.   # the middle, such as update.php/selection. The rule we use is strict,
  73.   # and only allows this pattern with the update.php front controller.
  74.   # This allows legacy path aliases in the form of
  75.   # blog/index.php/legacy-path to continue to route to Drupal nodes. If
  76.   # you do not have any paths like that, then you might prefer to use a
  77.   # laxer rule, such as:
  78.   #   location ~ \.php(/|$) {
  79.   # The laxer rule will continue to work if Drupal uses this new URL
  80.   # pattern with front controllers other than update.php in a future
  81.   # release.
  82.   location ~ '\.php$|^/update.php' {
  83.     fastcgi_split_path_info ^(.+?\.php)(|/.*)$;
  84.  
  85.     # Ensure the php file exists. Mitigates CVE-2019-11043
  86.     try_files $fastcgi_script_name =404;
  87.  
  88.     # Security note: If you're running a version of PHP older than the
  89.     # latest 5.3, you should have "cgi.fix_pathinfo = 0;" in php.ini.
  90.     # See http://serverfault.com/q/627903/94922 for details.
  91.  
  92.     include fastcgi_params;
  93.     # Block httpoxy attacks. See "HTTPOXY vulnerability".
  94.     fastcgi_param HTTP_PROXY "";
  95.     fastcgi_hide_header X-Powered-by;
  96.  
  97.     fastcgi_pass unix:/var/run/h8.sock;
  98.   }
  99.  
  100.   location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|ttf|woff)$ {
  101.     try_files $uri @rewrite;
  102.     expires max;
  103.     log_not_found off;
  104.   }
  105.  
  106.   # Fighting with Styles? This little gem is amazing.
  107.   # location ~ ^/sites/.*/files/imagecache/ { # For Drupal <= 6
  108.   location ~ ^/sites/.*/files/styles/ { # For Drupal >= 7
  109.     try_files $uri @rewrite;
  110.   }
  111.  
  112.   # Handle private files through Drupal. Private file's path can come
  113.   # with a language prefix.
  114.   location ~ ^(/[a-z\-]+)?/system/files/ { # For Drupal >= 7
  115.     try_files $uri /index.php?$query_string;
  116.   }
  117.  
  118.   # Enforce clean URLs
  119.   # Removes index.php from urls like www.example.com/index.php/my-page --> www.example.com/my-page
  120.   # Could be done with 301 for permanent or other redirect codes.
  121.   if ($request_uri ~* "^(.*/)index\.php/(.*)") {
  122.     return 307 $1$2;
  123.   }
  124. }

Ну что же, пора запускать веб-сервер, не забыв проверить перед его запуском конфиг на предмет отсутствия синтаксических ошибок:

  1. nginx -t
  2. nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
  3. nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful
  4.  
  5. echo 'nginx_enable="YES"' >> /etc/rc.conf
  6. service nginx start
  7.  
  8. ps -ax | grep nginx
  9. 50889  -  SJ   0:05,94 nginx: worker process (nginx)
  10. 50890  -  SJ   0:11,25 nginx: worker process (nginx)
  11. 50891  -  SJ   0:18,07 nginx: worker process (nginx)
  12. 50892  -  SJ   0:24,08 nginx: worker process (nginx)
  13. 64479  -  IsJ  0:00,21 nginx: master process /usr/local/sbin/nginx

Работает, а если нет, то смотрим логи. Добавлю, что как следует из конфига виртуального хоста nginx, он создан для сайта на движке Drupal. С учетом отсутствия в nginx поддержки обработки правил .htaccess, то по сравнению с Apache количество строк в конфиге виртуального хоста получилось примерно в 10 раз больше. В качестве образца я использовал пример конфига виртуального хоста для Drupal с официальной wiki nginx. На данном сайте есть множество полезных примеров настройки хостов для большинства популярных CMS и других веб-приложений. В случае отсутствия какого-либо примера, то разбираемся сами либо смотрим в документацию разработчика веб-приложения. Например, для Nextcloud пример конфигурирования виртуальног хоста можно посмотреть в его официальных доках.

Добавить комментарий

Этот вопрос задается для того, чтобы выяснить, являетесь ли Вы человеком или представляете из себя автоматическую спам-рассылку.