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 (в официальном репозитории пакетов она включена).
- pkg install nginx php74
Далее, немного расскажу о иерархии директорий сайтов у меня на сервере. У каждого пользователя домашней директорией является /home/username/data с правами 0750, в которой есть следующие поддиректории: logs, www, tmp. В директории www хранятся сайты, logs логи виртуальных хостов, а в tmp временные файлы PHP. Чтобы nginx мог получить к этим директориям доступ нужно добавить пользователя www в группу пользователя или можно воспользоваться ACL,ками, как сделал я:
- cd /home/h8/data
- mkdir logs tmp www
- chown www:www logs
- chown h8:h8 tmp www
- chmod 0755 logs
- chmod 0750 tmp
- chmod 0751 www
- setfacl -m u:www:x /home/h8
- setfacl -m u:www:x /home/h8/data
- setfacl -m u::rwx,g::rx,o::---,u:www:rx /home/h8/data/www
- 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. У меня настройки заданы следующим образом:
- ;;;;;;;;;;;;;;;;;;;;;
- ; Конфигурация FPM ;
- ;;;;;;;;;;;;;;;;;;;;;
- ; Конфигурационный файл заполняется в формате INI файла.
- ; Все относительные пути задаются относительно директории установки PHP (/usr/local).
- ; Данный префикс может быть изменен через параметр командной строки -p.
- ;;;;;;;;;;;;;;;;;;;;;;;;
- ; Глобальные параметры ;
- ;;;;;;;;;;;;;;;;;;;;;;;;
- [global]
- ; файл с идентификатором Pid
- ; Учтите: для данного параметра префикс: /var
- ; Значение по умолчанию: none
- pid = run/php-fpm.pid
- ; Файл для записи ошибок
- ; Если задано как "syslog", то логи будут направляться в syslogd, а не в локальный файл.
- ; Учтите: для данного параметра префикс: /var
- ; Значение по умолчанию: log/php-fpm.log
- error_log = log/php-fpm.log
- ; Используется для указания, какой тип программ будет логировать сообщения.
- ; Смотрите ман syslog(3) для получения информации о доступных значениях.
- ; Значение по умолчанию: daemon
- ;syslog.facility = daemon
- ; Предшествует любому сообщению. Если у вас запущено несколько экземпляры FPM,
- ; вы можете изменить значение по умолчанию на то, которое вам необходимо.
- ; Значение по умолчанию: php-fpm
- ;syslog.ident = php-fpm
- ; Уровень журналирования ошибок.
- ; Возможные значения: alert, error, warning, notice, debug
- ; Значение по умолчанию: notice
- log_level = warning
- ; Максимальное количество символов в строке.
- ; Если в сообщении будет превышен лимит символов, тогда оно будет разбито
- ; на несколько сообщений. Также учитываются символы, которые подставляются
- ; из prefix и suffix. However, the new line character does not count into it as it is present
- ; only when logging to a file descriptor. It means the new line character is not present
- ; when logging to syslog.
- ; Значение по умолчанию: 1024
- log_limit = 4096
- ; Переменная управляет поведением записи данных в файл.
- ; Если значение установлено в false , тогда данные записываются незамедлительно.
- ; Данный механизм является экспериментальным и разработан для
- ; сокращения количества записей на диск и потребляемой памяти.
- ; Опция игнорируется, если лог ведется в syslog.
- ; Значение по умолчанию: yes
- log_buffering = yes
- ; При указанном здесь количестве рабочих процессов, завершённых с SIGSEGV
- ; или SIGBUS за промежуток времени, установленный emergency_restart_interval,
- ; FPM будет перезагружен. Если параметр щадан в 0, тогда данный функционал
- ; не применяется.
- ; Значение по умолчанию: 0
- ;emergency_restart_threshold = 0
- ; Интервал времени, используемый emergency_restart_interval, чтобы определить,
- ; когда FPM будет перезагружен. Это может быть необходимо для избежания случайных
- ; повреждений в общей памяти ускорителя (accelerator). Доступные единицы измерения:
- ; s (секунды), m (минуты), h (часы), или d (дни).
- ; Единица измерения по умолчанию: секунды.
- ; Значение по умолчанию: 0 (Выключено).
- ;emergency_restart_interval = 0
- ; Время, в течение которого дочерние процессы ожидают ответа на сигналы,
- ; направленные мастер-процесса. Доступные единицы измерения:
- ; s (секунды), m (минуты), h (часы) или d (дни).
- ; Единица ; измерения по умолчанию: секунды.
- ; Значение по умолчанию: 0.
- process_control_timeout = 120s
- ; Максимальное количество процессов, которое может создать FPM.
- ; Опция необходима, чтобы контролировать общее количество порожденных процессов.
- ; Используйте с осторожностью, с учетом имеющихся ресурсов сервера.
- ; Учтите: если установлено в "0", значит ограничение отсутствует.
- ; Значение по умолчанию: 0
- process.max = 512
- ; Приоритет (Unix nice(2)) мастер-процесса (только если установлено).
- ; Допустимые значения от -19 (максимальный приоритет) до 20 (минимальный).
- ; Учтите: будет работать, если мастер-процесс запускается под root. В данном случае
- ; дочерние процессы будут наследовать приоритет мастер-процесса.
- ; Значение по умолчанию: no set
- process.priority = 19
- ; Запускать FPM в фоновом режиме. Если установлено в "no",
- ; то FPM запустится в режиме отладки.
- ; Значение по умолчанию: yes
- daemonize = yes
- ; Максимальное разрешенное количество одновременно открытых дескрипторов
- ; файлов для мастер-процесса.
- ; Значение по умолчанию: взятое с системы
- ;rlimit_files = 1024
- ; Максимальный размер корки для мастер-процесса.
- ; Доступные значения: 'unlimited' или целочисленное значения большее либо равное 0
- ; Значение по умолчанию: взятое с системы
- ;rlimit_core = 0
- ; Механизм обработки событий. Доступные значения ( в зависимости от ОС):
- ; - select (any POSIX os)
- ; - poll (any POSIX os)
- ; - epoll (linux >= 2.5.44)
- ; - kqueue (FreeBSD >= 4.1, OpenBSD >= 2.9, NetBSD >= 2.0)
- ; - /dev/poll (Solaris >= 7)
- ; - port (Solaris >= 10)
- ; Значение по умолчанию: not set (auto detection)
- events.mechanism = kqueue
- ; Если FPM собран с поддержкой systemd, тогда здесь возможно
- ; указать интервал времени в секундах, между оповещениями systemd
- ; о своём состоянии.
- ; Установите в 0, чтобы отключить.
- ; Доступные единицы измерения: s (секунды), m (минуты), h (часы).
- ; Единица ; измерения по умолчанию: секунды
- ; Значение по умолчанию: 10
- ;systemd_interval = 10
- ;;;;;;;;;;;;;;;;;;;;
- ; Pool Definitions ;
- ;;;;;;;;;;;;;;;;;;;;
- ; Каждый пул процессов может быть запущен на своем IP и порту (либо unix сокете)
- ; с различными параметрами выполнения. Имя пула должно быть уникальным
- ; и будет использоваться в логах и статистике. Количество пулов неограниченно.
- ; Your system will tell you anyway :)
- ; Подключите один или несколько файлов.
- ; Include one or more files. If glob(3) exists, it is used to include a bunch of
- ; files from a glob(3) pattern. This directive can be used everywhere in the file.
- ; Допустимо использовать относительные пути. Префикс может быть таким:
- ; - глобальный префикс, заданный через параметр -p
- ; - либо /usr/local
- include=/usr/local/etc/php-fpm.d/*.conf
Пример настройки пула /usr/local/etc/php-fpm.d/h8.conf:
- ; Объявляем новый пул с именем 'h8'.
- ; Переменная $pool может быть использована в любой директиве и будет заменена
- ; на имя пула, в данном случае на "h8".
- [h8]
- ; Префикс для пула. Используется только в следующих параметрах:
- ; - 'access.log'
- ; - 'slowlog'
- ; - 'listen' (unixsocket)
- ; - 'chroot'
- ; - 'chdir'
- ; - 'php_values'
- ; - 'php_admin_values'
- ; В случае если префикс не задан, используется глобальный (или /usr/local).
- ; Учтите: значение директивы может быть относительным глобального префикса.
- ; Значение по умолчанию: none
- prefix = /home/$pool/data
- ; Имя и группа, под которыми будет работать процессы в пуле.
- ; Учтите: указание директивы user обязательно. Если директива group не задана,
- ; тогда будет использована основная группа пользователя, указанного в user.
- user = h8
- group = h8
- ; Адрес, на котором пул процессов будет принимать запросы.
- ; Допустимые значения:
- ; 'ip.add.re.ss:port' - прием посредством TCP на конкретных IPv4 и порту
- ; '0.0.0.0:port' - прием посредтсвом TCP на любом IPv4 и конкретном порту
- ; '[ip:6:addr:ess]:port' - прием посредством TCP на конкретных IPv6 и порту
- ; 'port' - прием посредством TCP на любых (IPv6 and IPv4-mapped) и конкретном порту
- ; Учтите: IPv4-mapped addresses are disabled by-default in
- ; FreeBSD for security reasons;
- ; '/path/to/unix/socket' - прием посредством unix-сокета.
- ; Учтите: значение указывается в обязательном порядке.
- listen = /var/run/h8.sock
- ; В случае использования unix-сокета указываем права доступа к нему. В Linux, права
- ; read/write должны быть установлены таким образом, чтобы мог подключиться веб-сервер.
- ; Некоторые BSD системы допускают подключение независимо от прав доступа. Владелец
- ; сокета может быть указан по имени name либо ID.
- ; Значение по уполчанию: user и group мастер-процесса и права доступа 0660
- listen.owner = h8
- listen.group = www
- listen.mode = 0660
- ; В случае наличия поддержки POSIX Access Control Lists возможно задать
- ; через запятую user/group. Если этот параметр задан, тогда listen.owner
- ; и listen.group игнорируются.
- ;listen.acl_users =
- ;listen.acl_groups =
- ; Приоритет (Unix nice(2)) для процессов в пуле. Допустимые значения
- ; от -19 (максимальный приоритет) до 20 (минимальный).
- ; Учтите: будет работать, если мастер-процесс запускается под root. В данном случае
- ; дочерние процессы будут наследовать приоритет мастер-процесса, если параметр не задан.
- ; Значение по умолчанию: no set
- process.priority = 19
- ; Установить флаг процесса dumpable (PR_SET_DUMPABLE prctl), даже если пользователь
- ; процесса или группа отличается от пользователя мастер-процесса. Указанное позволяет
- ; создавать дамп памяти процесса и выполнить его ptrace.
- ; Значение по умолчанию: no.
- process.dumpable = no
- ; Здесь задается способ порождения процессов.
- ; Допустимые значения:
- ; static - фиксированное число дочерних процессов (pm.max_children)
- ; dynamic - переменное число дочерних процессов, задаётся на основании следующих директив.
- ; (With this process management, there will be always at least 1 children)
- ; pm.max_children
- ; pm.start_servers
- ; pm.min_spare_servers
- ; pm.max_spare_servers
- ; ondemand - дочерние процессы создаются только по требованию, задаётся
- ; на основании следующих директив:
- ; pm.max_children
- ; pm.process_idle_timeout
- ; Учтите: задание параметра является обязательным.
- pm = dynamic
- ; Количество процессов, создаваемых в режиме "static", а в случае режимов
- ; "dynamic" или "ondemand" :nbsp; максимальное количество процессов,
- ; работающих одновременно. Фактически данный параметр ограничивает
- ; количество одновременно обрабатываемых запросов.
- ; Действие параметра аналогично директиве ApacheMaxClients сервера Apache
- ; с MPM модудем mpm_prefork и аналогично переменной окружения PHP_FCGI_CHILDREN
- ; в оригинальном PHP CGI. Значение по умолчанию выбрано без учета мощности оборудования.
- ; Необходимо настраивать параметры pm.* под свои нужды.
- ; Учтите: указание значения обязательно.
- pm.max_children = 7
- ; Количество процессов в пуле, создаваемых на этапе запуска.
- ; Учтите: оказывает влияние только в режиме 'dynamic'.
- ; Значение по умолчанию: (min_spare_servers + max_spare_servers) / 2
- ; pm.start_servers = 1
- ; Минимальное количество неактивных (простаивающих) процессов пула.
- ; Используется только, когда pm установлено в "dynamic".
- ; Учтите: указание значения обязательно.
- pm.min_spare_servers = 1
- ; Макималное количество неактивных (простаивающих) процессов пула.
- ; Используется только, когда pm установлено в "dynamic".
- ; Учтите: указание значения обязательно.
- pm.max_spare_servers = 5
- ; Время в секундах, по истечению которого неактивный (простаивающий)
- ; процесс будет уничтожен.
- ; Используется только, когда pm установлено в "ondemand".
- ; Значение по уполчанию: 10s
- ;pm.process_idle_timeout = 10s;
- ; Количество обработанных каждым процессом из пула запросов, после
- ; которого процесс будет уничтожен и создан заного. Данный функционал может
- ; быть полезен для профилактики утечки памяти в случае наличия багов в сторонних
- ; библиотеках. Отключение функции осуществляется установкой параметра в 0.
- ; По своей сути функционал аналогичен PHP_FCGI_MAX_REQUESTS.
- ; Значение по умолчанию: 0
- pm.max_requests = 1000
- ; Путь до файла, в который будут записываться данные об обработанных запросах (лог доступа).
- ; Значение по умолчанию: not set
- ;access.log = log/$pool.access.log
- ; Формат записей в лог доступа.
- ; Допустим следующий синтаксис:
- ; %%: the '%' character
- ; %C: %CPU used by the request
- ; it can accept the following format:
- ; - %{user}C for user CPU only
- ; - %{system}C for system CPU only
- ; - %{total}C for user + system CPU (default)
- ; %d: time taken to serve the request
- ; it can accept the following format:
- ; - %{seconds}d (default)
- ; - %{miliseconds}d
- ; - %{mili}d
- ; - %{microseconds}d
- ; - %{micro}d
- ; %e: an environment variable (same as $_ENV or $_SERVER)
- ; it must be associated with embraces to specify the name of the env
- ; variable. Some exemples:
- ; - server specifics like: %{REQUEST_METHOD}e or %{SERVER_PROTOCOL}e
- ; - HTTP headers like: %{HTTP_HOST}e or %{HTTP_USER_AGENT}e
- ; %f: script filename
- ; %l: content-length of the request (for POST request only)
- ; %m: request method
- ; %M: peak of memory allocated by PHP
- ; it can accept the following format:
- ; - %{bytes}M (default)
- ; - %{kilobytes}M
- ; - %{kilo}M
- ; - %{megabytes}M
- ; - %{mega}M
- ; %n: pool name
- ; %o: output header
- ; it must be associated with embraces to specify the name of the header:
- ; - %{Content-Type}o
- ; - %{X-Powered-By}o
- ; - %{Transfert-Encoding}o
- ; - ....
- ; %p: PID of the child that serviced the request
- ; %P: PID of the parent of the child that serviced the request
- ; %q: the query string
- ; %Q: the '?' character if query string exists
- ; %r: the request URI (without the query string, see %q and %Q)
- ; %R: remote IP address
- ; %s: status (response code)
- ; %t: server time the request was received
- ; it can accept a strftime(3) format:
- ; %d/%b/%Y:%H:%M:%S %z (default)
- ; The strftime(3) format must be encapsuled in a %{<strftime_format>}t tag
- ; e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t
- ; %T: time the log has been written (the request has finished)
- ; it can accept a strftime(3) format:
- ; %d/%b/%Y:%H:%M:%S %z (default)
- ; The strftime(3) format must be encapsuled in a %{<strftime_format>}t tag
- ; e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t
- ; %u: remote user
- ;
- ; Значение по умолчанию: "%R - %u %t \"%m %r\" %s"
- ;access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%"
- ; Путь до файла, в который будут записываться данные о медленных запросах.
- ; Значение по умолчанию: not set
- ; Учтите: задание параметра обязательно при указании параметра request_slowlog_timeout
- ;slowlog = log/$pool.log.slow
- ; Время, после которого выполняемых запрос будет считаться медленным, в результате чего
- ; данные об этом будут записаны в файл 'slowlog'. Значение '0' отключает данный функционал.
- ; Доступные единицы измерения: s (секунды, по умолчанию), m (минуты), h (часы) или d (дни).
- ; Значение по умолчанию: 0
- ;request_slowlog_timeout = 0
- ; Информативность (глубина) записей в slowlog.
- ; Значение по умолчанию: 20
- ;request_slowlog_trace_depth = 20
- ; Максимальное время обработки запроса, при превышении которого
- ; процесс будет уничтожен. Данный параметр может оказаться полезным,
- ; в случае если PHP параметр 'max_execution_time' не сработает по какой-либо
- ; причине. Значение в 0 отключает данный функционал.
- ; Доступные единицы измерения: s (секунды, по умолчанию), m (минуты), h (часы) или d (дни).
- ; Значение по уполчанию: 0
- ;request_terminate_timeout = 0
- ; The timeout set by 'request_terminate_timeout' ini option is not engaged after
- ; application calls 'fastcgi_finish_request' or when application has finished and
- ; shutdown functions are being called (registered via register_shutdown_function).
- ; This option will enable timeout limit to be applied unconditionally
- ; even in such cases.
- ; Default Value: no
- ;request_terminate_timeout_track_finished = no
- ; Вы полнить chroot() в указанную здесь директорию после запуска процесса.
- ; Путь к директории должен быть полным (абсолютным). Если значение не задано,
- ; тогда chroot() не применяется.
- ; Учтите: возможно использовать пеерменную $prefix, указанную ранее для пула.
- ; Если префикс для пула не указывался, тогда будет использован глобальный префикс.
- ; Учтите: chroot является мощным интрументом безопасности и должен
- ; использоваться во всевозможных случаях. Однако следует учитывать,
- ; что все пути для PHP будут относительны указанной здесь директории
- ; (error_log, sessions.save_path, ...).
- ; Значение по умолчанию: not set
- ;chroot =
- ; Выполнить chdir в директорию после старта.
- ; Учтите: может быть указан относительный путь.
- ; Значение по уполчанию: текущая директория или / при использовании chroot.
- ;chdir = /var/www
- ; Перенаправление STDOUT и STDERR рабочего процесса в главный лог ошибок.
- ; Если не установлен, тогда вывод STDOUT и STDERR будет перенаправлен в /dev/null
- ; в соответствии со спецификацией FastCGI.
- ; Note: on highloaded environement, this can cause some delay in the page
- ; process time (several ms).
- ; Значение по умолчанию: no.
- ;catch_workers_output = yes
- ; Decorate worker output with prefix and suffix containing information about
- ; the child that writes to the log and if stdout or stderr is used as well as
- ; log level and time. This options is used only if catch_workers_output is yes.
- ; Settings to "no" will output data as written to the stdout or stderr.
- ; Default value: yes
- ;decorate_workers_output = no
- ; Удалить переменные окружения для процессов из пула, таким образом
- ; предотвратив утечку чувствительных данных через указанные переменные
- ; Установка в "no" будет означать, что к информации из переменных окружения,
- ; действовавших на этапе создания процесса, можно будет получить доступ
- ; в скриптах через getenv(), $_ENV и $_SERVER.
- ; Значение по уполчанию: yes
- clear_env = yes
- ; Здесь возможно указать расширения файлов, которые PHP-FPM
- ; будет воспринимать в качестве скриптов. Данный механизм
- ; поможет обезопасить сервер при наличии упущений в конфигурации
- ; веб-сервера (например, всем известная фишка с cgi.fix_path_info).
- ; Следует ограничить FPM обрабатывать файлы только с расширеним .php
- ; для исключения подстановки вредоносного когда через файлы
- ; с иными расширениями.
- ; Учтите: оставьте значение пустым, чтобы разрешить FPM выполнять любые файлы
- ; Значение по уполчанию: .php
- security.limit_extensions = .php .php3 .php4 .php5 .php7
- ; Задать переменные окружения для скриптов.. Все $VARIABLEs будут
- ; взяты из исходного окружения.
- ; Значение по умолчанию: clean env
- ;env[HOSTNAME] = $HOSTNAME
- env[PATH] = /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/root/bin
- env[TMP] = /home/h8/data/tmp
- env[TMPDIR] = /home/h8/data/tmp
- env[TEMP] = /home/h8/data/tmp
- ; Additional php.ini defines, specific to this pool of workers. These settings
- ; overwrite the values previously defined in the php.ini. The directives are the
- ; same as the PHP SAPI:
- ; php_value/php_flag - you can set classic ini defines which can
- ; be overwritten from PHP call 'ini_set'.
- ; php_admin_value/php_admin_flag - these directives won't be overwritten by
- ; PHP call 'ini_set'
- ; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no.
- ; Defining 'extension' will load the corresponding shared extension from
- ; extension_dir. Defining 'disable_functions' or 'disable_classes' will not
- ; overwrite previously defined php.ini values, but will append the new value
- ; instead.
- ; Note: path INI options can be relative and will be expanded with the prefix
- ; (pool, global or /usr/local)
- ; Default Value: nothing is defined by default except the values in php.ini and
- ; specified at startup with the -d argument
- php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f admin@example.ru
- php_value[error_reporting] = E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED
- php_flag[display_errors] = Off
- php_value[default_charset] = "UTF-8"
- php_flag[log_errors] = On
- php_admin_value[error_log] = /home/h8/data/logs/php-errors.log
- php_admin_value[max_input_time] = 120
- php_admin_value[max_execution_time] = 120
- php_admin_value[memory_limit] = 256M
- php_admin_value[upload_max_filesize] = 16M
- php_admin_value[post_max_size] = 32M
- php_value[date.timezone] = Europe/Moscow
- php_admin_value[open_basedir] = .:/home/h8/data/:/usr/local/share/pear/:/dev/urandom
- php_admin_value[upload_tmp_dir] = /home/h8/data/tmp
- php_admin_value[session.save_path] = /home/h8/data/tmp
- php_admin_flag[session.bug_compat_42] = Off
- php_admin_flag[session.bug_compat_warn] = Off
- php_admin_value[session.gc_divisor] = 1000
- php_admin_value[session.hash_bits_per_character] = 5
- php_admin_flag[expose_php] = Off
- php_admin_value[variables_order] = GPCS
- php_admin_value[request_order] = GP
- php_admin_flag[register_argc_argv] = Off
- php_admin_value[auto_globals_jit] = On
- ; Drupal config from .htaccess
- php_admin_value[assert.active] = 0
- php_admin_flag[session.auto_start] = off
- php_admin_value[mbstring.http_input] = pass
- php_admin_value[mbstring.http_output] = pass
- php_admin_flag[mbstring.encoding_translation] = off
- ; PHP 5.6 has deprecated $HTTP_RAW_POST_DATA and produces warnings
- ; if this is not set.
- php_admin_value[always_populate_raw_post_data] = -1
- php_admin_value[opcache.enable] = 1
- php_admin_value[opcache.memory_consumption] = 128
- php_admin_value[opcache.interned_strings_buffer] = 16
- php_admin_value[opcache.max_accelerated_files] = 8000
- php_admin_value[opcache.revalidate_freq] = 60
- php_admin_value[opcache.save_comments] = 1
- php_admin_value[opcache.fast_shutdown] = 1
- php_admin_value[opcache.enable_cli] = 1
- php_admin_value[apc.enabled] = 0
- php_flag[verify_peer] = off
- php_flag[verify_peer_name] = off
Стоит отметить одну особенность работы PHP-FPM, а именно невозможность загрузки различных модулей расширения PHP для пулов. То есть модули расширения загружаются однократно мастер-процессом и далее видны всем дочерним процессам. Если в какой-то ситуации необходимо создать пулы с различным набором подгруженных модулей , тогда целесообразно запускать несколько мастер-процессов с разной конфигурацией. Другим более простым вариантом является отключение функционала модулей через php_admin_value.
Итак, после настройки конфигов для PHP-FPM стоит попробовать его запустить, для чего делаем следующее:
- echo 'php_fpm_enable="YES"' >> /etc/rc.conf
- service php-fpm start
- ps -ax | grep php
- 5302 - INJ 7:01,56 php-fpm: pool h8 (php-fpm)
- 5303 - INJ 7:07,16 php-fpm: pool h8 (php-fpm)
- 18592 - INJ 0:35,04 php-fpm: pool h8 (php-fpm)
- 25324 - INJ 0:20,32 php-fpm: pool h8 (php-fpm)
- 29026 - INJ 5:26,86 php-fpm: pool h8 (php-fpm)
- 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. Далее, приведу содержимое указанного файла с комментариями по ходу следования параметров:
- # Задаём пользователя и группу, с правами которого будут работать рабочие процессы.
- # Если группа не задана, то используется группа, имя которой совпадает с именем пользователя.
- user www;
- # Задаёт число рабочих процессов. Оптимально значение равное количеству ядер в системе.
- # Также возможно указать значение auto.
- # У меня nginx скомпилирован с модулем GeoIP2, поэтому я его тут подгружаю
- load_module /usr/local/libexec/nginx/ngx_http_geoip2_module.so;
- # This default error log path is compiled-in to make sure configuration parsing
- # errors are logged somewhere, especially during unattended boot when stderr
- # isn't normally logged anywhere. This path will be touched on every nginx
- # start regardless of error log location configured here. See
- # https://trac.nginx.org/nginx/ticket/147 for more info.
- #
- error_log /var/log/nginx/error.log;
- events {
- # Задаёт метод, используемый для обработки соединений (если не указан,
- # то nginx сам выбирает наиболее эффективный метод).
- use kqueue;
- # Задаёт максимальное число соединений, которые одновременно может открыть рабочий процесс.
- worker_connections 1024;
- }
- http {
- # Разрешает или запрещает выдавать версию nginx’а на страницах ошибок
- # и в поле “Server” заголовка ответа.
- server_tokens off;
- # На официальном сайте к nginx есть описание всех доступных переменных
- log_format main '$remote_addr - $remote_user [$time_local] "$request" '
- '$status $body_bytes_sent "$http_referer" '
- '"$http_user_agent" "$http_x_forwarded_for"';
- # Параметры SSL
- # Время, в течение которого nginx будет хранить параметры SSL сессии клиента
- # Кэшируем SSL сесси для того чтобы сократить количество рукопожатий SSL с клиентами,
- # таким образом снижая нагрузку на процессор.Тип и размеры кэшей для хранения
- # параметров SSL сессий (20m ~ 80000 сессий)
- ssl_session_cache shared:nginxSSL:20m;
- ssl_session_tickets off; # Запрещаем возобновление сессий при помощи TLS session tickets.
- # Данные параметры получены в генераторе от Mozilla (в конце статьи есть ссылка)
- ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
- 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;
- sendfile on;
- #tcp_nopush on;
- # TCP options
- # Ничего особенного, подбираются индивидуально
- keepalive_requests 1000;
- keepalive_time 5m;
- keepalive_timeout 65s;
- # GeoIP options
- geoip2 /usr/local/share/GeoIP/GeoLite2-Country.mmdb {
- auto_reload 1d; # через какой время nginx будт перезагружать базу
- # $variable_name metadata <field>
- # Доступные значения:
- # build_epoch: время создания ьазы данных maxmind.
- # last_check: время, когда база последний раз была проверена на предмет изменений (when using auto_reload)
- # last_change: время, когда база последний раз была перезагружена (when using auto_reload)
- #$geoip2_metadata_country_build metadata build_epoch;
- # $variable_name [default=<value] [source=$variable_with_ip] path ...
- # Структуру базы можно подглядеть так: mmdblookup --file /path/to/GeoLite2-Country.mmdb --ip 127.0.0.1
- $geoip2_data_continent_code continent code;
- $geoip2_data_country_code country iso_code;
- $geoip2_data_country_name country names en;
- }
- geoip2 /usr/local/share/GeoIP/GeoLite2-City.mmdb {
- auto_reload 1d;
- $geoip2_data_city_name city names en;
- $geoip2_data_region subdivisions 0 names en;
- }
- # Все виртуальные хосты у меня описаны в конфигурационных файлах в этой поддиректории
- include vhosts/*.conf;
- }
В директории /usr/local/etc/nginx имеется файл fastcgi_params, в котором задаются переменные окружения, передаваемые клиенту. Я его немного подредактировал с учетом наличия модуля GeoIP2, а также убрал вывод версии nginx и добавил переменную SCRIPT_FILENAME.
- fastcgi_param GATEWAY_INTERFACE CGI/1.1;
- fastcgi_param SERVER_SOFTWARE nginx;
- # PHP only, required if PHP was built with --enable-force-cgi-redirect
- fastcgi_param REDIRECT_STATUS 200;
- # GeoIP
Ну и теперь настраиваем виртуальный хост:
- server {
- listen 80;
- server_name example.org;
- # Пути до лог файлов
- error_log /home/h8/data/logs/example.org.error.log;
- access_log /home/h8/data/logs/example.org.access.log main;
- # HTTP response headers borrowed from Drupal `.htaccess`
- # Включаем сжатие gzip ( but do not remove ETag headers)
- gzip on;
- gzip_vary on;
- gzip_min_length 256;
- 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;
- allow all;
- log_not_found off;
- access_log off;
- }
- log_not_found off;
- access_log off;
- }
- # Block access to scripts in "site" "files" directory
- # Allow "Well-Known URIs" as per RFC 5785
- # Deny access to .htaccess files, if Apache's document root
- # concurs with nginx's one
- location / {
- # try_files $uri @rewrite; # For Drupal <= 6
- }
- # Block access to "hidden" files and directories whose names begin with a
- # period. This includes directories used by version control systems such
- # as Subversion or Git to store control files.
- # Don't allow direct access to PHP files in the vendor directory.
- deny all;
- return 404;
- }
- # Protect files and directories from prying eyes.
- 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)$ {
- deny all;
- return 404;
- }
- #rewrite ^/(.*)$ /index.php?q=$1; # For Drupal <= 6
- }
- # Workaround Drupal bug #2583799 - https://www.drupal.org/node/2583799
- # In Drupal 8, we must also match new paths where the '.php' appears in
- # the middle, such as update.php/selection. The rule we use is strict,
- # and only allows this pattern with the update.php front controller.
- # This allows legacy path aliases in the form of
- # blog/index.php/legacy-path to continue to route to Drupal nodes. If
- # you do not have any paths like that, then you might prefer to use a
- # laxer rule, such as:
- # location ~ \.php(/|$) {
- # The laxer rule will continue to work if Drupal uses this new URL
- # pattern with front controllers other than update.php in a future
- # release.
- # Ensure the php file exists. Mitigates CVE-2019-11043
- # Security note: If you're running a version of PHP older than the
- # latest 5.3, you should have "cgi.fix_pathinfo = 0;" in php.ini.
- # See http://serverfault.com/q/627903/94922 for details.
- include fastcgi_params;
- # Block httpoxy attacks. See "HTTPOXY vulnerability".
- fastcgi_hide_header X-Powered-by;
- fastcgi_pass unix:/var/run/h8.sock;
- }
- expires max;
- log_not_found off;
- }
- # Fighting with Styles? This little gem is amazing.
- # location ~ ^/sites/.*/files/imagecache/ { # For Drupal <= 6
- }
- # Handle private files through Drupal. Private file's path can come
- # with a language prefix.
- }
- # Enforce clean URLs
- # Removes index.php from urls like www.example.com/index.php/my-page --> www.example.com/my-page
- # Could be done with 301 for permanent or other redirect codes.
- return 307 $1$2;
- }
- }
Ну что же, пора запускать веб-сервер, не забыв проверить перед его запуском конфиг на предмет отсутствия синтаксических ошибок:
- nginx -t
- nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
- nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful
- echo 'nginx_enable="YES"' >> /etc/rc.conf
- service nginx start
- ps -ax | grep nginx
- 50889 - SJ 0:05,94 nginx: worker process (nginx)
- 50890 - SJ 0:11,25 nginx: worker process (nginx)
- 50891 - SJ 0:18,07 nginx: worker process (nginx)
- 50892 - SJ 0:24,08 nginx: worker process (nginx)
- 64479 - IsJ 0:00,21 nginx: master process /usr/local/sbin/nginx
Работает, а если нет, то смотрим логи. Добавлю, что как следует из конфига виртуального хоста nginx, он создан для сайта на движке Drupal. С учетом отсутствия в nginx поддержки обработки правил .htaccess, то по сравнению с Apache количество строк в конфиге виртуального хоста получилось примерно в 10 раз больше. В качестве образца я использовал пример конфига виртуального хоста для Drupal с официальной wiki nginx. На данном сайте есть множество полезных примеров настройки хостов для большинства популярных CMS и других веб-приложений. В случае отсутствия какого-либо примера, то разбираемся сами либо смотрим в документацию разработчика веб-приложения. Например, для Nextcloud пример конфигурирования виртуальног хоста можно посмотреть в его официальных доках.