open basedir php fpm
Для чего нужна и как использовать open_basedir
Директива open_basedir указывается в конфигурационном файле PHP (php.ini) и устанавливает директории, к которым может иметь доступ PHP. Под доступом понимаются любые действия с файлами: открытие (например, функции fopen() или gzopen()), записи и выполнения. Если директива open_basedir установлена и делается попытка запустить файл, который находится за пределами перечисленных директорий, то скрипт не запустится и выдаст ошибку:
Пример значения open_basedir:
В указанном примере разрешён запуск скриптов PHP, а также операции с файлами в директориях:
Директива open_basedir оказывает влияние на многие функции. Больше всего в ней смысла при использовании на уровне конфигурационных файлов веб-сервера на уровне директорий или виртуальных хостов.
По умолчанию, если значение open_basedir не установлено, разрешены файловые операции в любых директориях компьютера (на которые достаточно прав).
Специальное значение . (точка) обозначает, что рабочая директория скрипта будет использована в качестве базовой директории. Однако, это немного опасно, так как текущая директория скрипта может быть легко изменена с помощью chdir().
В httpd.conf, open_basedir может быть выключена (например, для некоторых виртуальных хостов) тем же способом, что и любая другая конфигурационная директива:
В Windows разделяйте директории символом ; (точкой с запятой). На всех остальных системах, разделяйте директории символом : (двоеточием). При работе в качестве модуля Apache, пути open_basedir автоматически наследуются от родительских директорий.
VestaCP open_basedir php-fpm
По умолчанию, на сегодняшний день, связка Nginx+PHP-FPM в VetaCP не позволяет подключить open_basedir. Однако, панель работает с системой шаблонов, и с их помощью мы можем сделать всё необходимое.
Настраиваем open_basedir.
1. Для php-fpm шаблоны VestaCP хранит в директории /usr/local/vesta/data/templates/web/ Переходим туда, и либо создаём новый файл-шаблона, либо редактируем уже имеющийся, нужный нам (socket.tpl в моём случае).
2. Открываем файл socket.tpl и прописываем в нём строку:
В данном случае, мы разрешаем доступ к двум директориям конкретного пользователя — к директории с файлами доменов, и к директории для временных файлов. Файл сохраняем.
3. В панели переходим к настройкам доменного имени, и для Backend Template выбираем наш шаблон.
Сохраняем изменения, и проверяем phpinfo();, в котором переменная open_basedir примет заданные нами ранее значения.
Проверяем ограничения.
Проверить, срабатывает ли open_basedir легко. В директории с сайтом создадим вот такой простой php скрипт:
И попробуем обратиться к нему из браузера. https://domain.com/in223.php
В логах должно осесть примерно следующее:
Это означает, что запрос к файлу вне разрешённых директорий был ограничен системой.
Дополнительно здесь стоит учесть, что даже при активном open_basedir, в PHP имеются функции, с помощью которых можно обойти ограничения. Например, с помощью shell_exec можно прочитать содержимое файла, либо выполнить нужную команду. Такие функции лучше сразу же отключить в disable_functions. Тогда и с их помощью прочитать что-то лишнее не удастся:
PHP open_basedir
How to enabled PHP open_basedir in CWP
** Note this is only for PHP-CGI
We have two options
— global config, one config file in the include folder /usr/local/php/php.d/ and in PHP selector include folders
— per-user config, the securest option as it restricts the user to his /home/USERNAME folder and also disables users from using custom php.ini files.
Global Configuration
The securest method do this correctly and to prevent users from overriding this is to place the config into the include file. Please note that if you set this into /usr/local/php/php.ini then custom user php.ini will be able to disable it. Please note that global config allows full /home folder access while per user restricts users to /home/USERNAME folder which is much more secure.
One line command to create a file and config:
You can also do it by yourself by creating a file: /usr/local/php/php.d/open_basedir.ini with the following content:
To enable it for other php versions from the PHP selector you can create this config files with the same content:
PHP info file example phpinfo.php
** Don’t forget to replace the USERNAME.
Please note that this option will also disable all further custom users php.ini files per folder, for example: /home/USERNAME/public_html/php.ini will not be loaded.
You can also place it into public_html folder but then users will be able to run custom php.ini files per folder and they can disable open_basedir.
RECOMMENDATION
We recommend using the per-user configuration of open_basedir as it will provide much higher security and isolate each client.
NGINX + PHP-FPM
configuration files are:
/etc/nginx/conf.d/vhosts/DOMAIN.conf
/etc/nginx/conf.d/vhosts/DOMAIN.ssl.conf
under fastcgi_param add one more line and reload/restart nginx
** Note that manual editing of the webserver vhost files is not recommended as those files get rebuilt from the template on each change.
Try checking the instructions here for the custom template build.
APACHE + PHP-FPM
Configuration files are all user existing php-fpm configuration files, to get the list of files you can use this
** Note that editing any of those files requires to restart php-fpm version you edited.
** Note that manual editing of the webserver vhost files is not recommended as those files get rebuilt from the template on each change.
Try checking the instructions here for the custom template build.
Настройка PHP-FPM
Интерпретатор языка программирования PHP может работать в нескольких режимах. Он может быть интегрирован в веб-сервер в виде специального модуля или использоваться как отдельный сервис php-fpm. Аббревиатура FPM расшифровывается как Fastcgi Process Manager. Это сервис, который запускает несколько процессов, которые могут выполнять PHP скрипты. Процессы могут получить скрипты, которые надо выполнить по TCP или Unix сокетам.
Обычно php-fpm используется вместе с веб-сервером Nginx. В этой статье мы рассмотрим как выполняется настройка PHP-FPM для максимально эффективной работы на вашем сервере.
Настройка PHP-FPM
Менеджер процессов PHP-FPM может запускать несколько процессов обработчиков. Обычно для каждого отдельного сайта принято использовать отдельный обработчик, это позволяет распределить нагрузку и отслеживать статистику по каждому сайту. Поэтому есть общий конфигурационный файл php-fpm и конфигурационный файл для каждого обработчика, который обычно называется конфигурационным файлом пула. Обработчик принято называть пулом потому что на самом деле обработкой занимается не один процесс, а целая группа процессов, у каждого из которых есть несколько потоков. Всё это обеспечивает быстрое выполнение скриптов.
1. Установка компонентов
Сервис php-fpm поставляется вместе с интерпретатором php. Установка php-fpm Ubuntu выполняется такой командой:
sudo apt install php-fpm
Кроме того нам понадобится веб-сервер Nginx, потому что php-fpm чаще всего используется вместе с этим веб-сервером:
sudo apt install nginx
2. Конфигурационные файлы
В этой инструкции мы будем рассматривать настройку PHP-FPM на примере Ubuntu. Основной конфигурационный файл находится в такому пути:
Обратите внимание, что это не php.ini файл, а файл настройки именно FPM процессов. Файл php.ini находится в этой же папке:
А вот файлы конфигурации пулов находятся в каталоге /etc/php/7.4/fpm/pool.d/. По умолчанию там находится файл пула по умолчанию www.conf:
Вы можете использовать его в своей конфигурации или копировать для создания новых пулов.
3. Создание пула
Скопируйте файл пула, например losst.conf в папке /etc/php/7.4/fpm/pool.d/ скопируйте в него содержимое файла www.conf. В конце статьи я приведу полностью рабочий конфигурационный файл, но лучше всё же использовать конфигурацию вашей версии PHP:
cp /etc/php/7.4/fpm/pool.d/www.conf /etc/php/7.4/fpm/pool.d/losst.conf
Теперь откройте этот файл в текстовом редакторе, например в vim:
sudo vi /etc/php/7.4/fpm/pool.d/losst.conf
Далее надо изменить группу и пользователя, от имени которых будут запускаться процессы пула. Это важно, поскольку у процесса должен быть доступ к файлам PHP, которые надо выполнить. Обычно в Ubuntu для таких целей используется пользователь и группа www-data. От имени этого же пользователя обычно запускается веб-сервер:
Обычно, если вы получаете ошибку permission denied при интерпретации php файлов в php-fpm, означает, что процесс php-fpm запущен от имени не того пользователя или включена строгая политика SELinux.
4. Настройка сокета
Если вы используйте файловый сокет, к нему должен быть доступ у веб-сервера, поэтому надо сделать владельцами файла того пользователя и группу, от имени которых запущен веб-сервер, в данном случае www-data и дать им все права на него:
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
Если сокет сетевой, то в этом нет необходимости. Для сетевого сокета можно дополнительно указать с каких адресов можно к нему подключаться. Например, только от 127.0.0.1:
5. Настройка процессов
С помощью параметра pm можно настроить сколько дочерних процессов будет запускаться для этого пула и когда. Есть три режима работы:
Режим static не выгоден, потому что вне зависимости от нагрузки потребляется много памяти и процессорного времени на поддержание работы процессов. Более интересны режимы ondemand и dynamic. Давайте будем использовать режим dynamic. Этот режим имеет три настройки:
Для режима static надо указать только pm.max_children. Для режима ondemand кроме pm.max_children надо указать pm.process_idle_timeout этот параметр означает через какой промежуток времени простоя процесс будет завершен.
Давайте разберемся с режимом dynamic. Запускать много дочерних процессов при старте не надо, в большинстве случаев 2-3 будет достаточно:
Минимальное количество процессов в режиме ожидания тоже большое не нужно, это запас, чтобы php-fpm смог быстро обработать новые запросы не тратя время на запуск новых процессов. Однако это значение должно быть не меньше pm.start_servers, иначе ничего не заработает:
Максимальное количество процессов определяет как быстро процессы будут завершаться при падении нагрузки, можно оставить 10 процессов:
Параметр pm.max_children настройте под себя, обычно достаточно 20-30 процессов, но всё зависит от нагрузки и количества оперативной памяти, если памяти мало лучше пожертвовать производительностью и установить меньшее значение:
Почти готово. Но есть ещё одна проблема. Если дочерние процессы работают слишком долго, в них накапливаются утечки памяти, и рано или поздно на сервере память закончится. Чтобы этого избежать можно настроить автоматическое завершение процесса после выполнения определённого количества запросов, например, 1000:
6. Настройка статистики
Для подбора оптимального значения pm.max_children вам может понадобиться посмотреть статистику в реальном времени сколько процессов запущено, сколько из них находится в ожидании, а также какая длина очереди ожидающих выполнения запросов. Для включения вывода статистики просто добавьте такую строчку:
7. Настройка php.ini
php_admin_flag[display_errors] = off
php_admin_value[error_log] = /var/log/fpm-php.losst.log
php_admin_flag[log_errors] = on
php_admin_value[memory_limit] = 32M
Когда все настройки завершены, не забудьте сохранить изменения и перезапустить php-fpm:
sudo systemctl restart php7.4-fpm
8. Настройка веб-сервера
Для того чтобы всё протестировать придётся настроить ещё и веб-сервер. В конфигурационный файл виртуального хоста Nginx надо добавить такие строки:
Последняя директива fastcgi_pass указывает как надо передавать данные php-fpm, сюда можно передать путь к файлу сокету, на котором слушает сервис или IP адрес и порт. В данном случае используется ранее настроенный 127.0.0.1:9000. После завершения настройки перезапустите Nginx:
sudo systemctl restart nginx
Теперь вы можете открыть в браузере страницу статистики, как видите всё работает:
Можно ещё создать файл phpinfo.php с текстом в каталоге веб-сервера и посмотреть настройки php, например, memory_limit, заданный в файле конфигурации пула работает:
Настройка веб-сервера может очень сильно отличаться в зависимости от ваших требований. Здесь приведен только общий пример, чтобы проверить работоспособность и верность настройки.
I installed a fresh Debian 7.5 server and installed NGINX and PHP FPM from the default debian packages.
Then I’ll added 2 new users vhosta and vhostb and added the NGINX webserver user www-data to the group of each user.
Next I created the following directory structure.
I configured an individual PHP FPM pool for each virtual host to seperate the PHP processes for each virtual host. The configuration is as following (just showing for vhosta )
So far, so good. I installed a PHP application (CMS) in vhosta and did some performance testing with ApacheBench.
Generally, everything runs more smooth and fast than with Apache2 and I’ll end up with the following result.
Well, 31.62 requests per second is fine for me at this point.
Last I want to access restrict both vhosta and vhostb to a subset of directories, so they do not have access to other world readable system files. I do so, by using the PHP directive open_basedir.
I have added the following to each virtial hosts PHP FPM pool (just showing vhosta )
Doing so, the vhosts should not be able to access e.g. /etc/passwd. I created a simple PHP script, which verifies, that the vhosts can’t access files outside from the configured directories.
Finally, I repeated the performance test and end up with the following result.
It seems, that adding an open_basedir directive to the PHP FPM pool causes a big performance decreasement. Access times and the amount of requests per second is now fairly similar compared to a setup using Apache2 with mod_php.
My questions are as following:
Can the setup I created be considered as «secure», so the individual vhosts can’t access each other? If not, what is best practice to do so and what am I missing?
Why does the performance decrease so much, when I use open_basedir? Or is it save to not use open_basedir, since files like /etc/passwd are world readable anyway?