- Вопрос или проблема
- Моя настройка
- Apache
- Vhost
- PHP FPM
- pool.d/www.conf
- Журналы ошибок
- Как исправить / исследовать?
- Правка / важное примечание
- Если корень документа, доступный для Apache, отличается от корня документа, доступного для PHP-FPM
- Ответ или решение
- Настройка Apache с PHP-FPM: ошибка "Файл не найден"
- Основные аспекты конфигурации
- Анализ проблемы
- Решение проблемы
- Заключение
Вопрос или проблема
Я много искал в Google, и действительно есть много результатов (даже на serverfault.com) по этой проблеме. Однако мне не удалось решить свои проблемы с ней.
Моя настройка
Я настраиваю Ubuntu 20 на WSL2 и пытаюсь обеспечить его с помощью Ansible. Я пытаюсь настроить Apache с PHP-FPM-7.4.
Apache
Apache, похоже, работает нормально. У меня есть корневая директория с файлом test.html. Когда я вызываю прямой URL к этому HTML-файлу, я вижу его содержимое, как и положено.
Vhost
Примечание: для удобства чтения я пропустил все комментарии
DirectoryIndex index.php index.html
<VirtualHost *:80>
ServerName paul.test
ServerAlias *.paul.test
<FilesMatch \.php$>
Require all granted
SetHandler proxy:fcgi://127.0.0.1:9000
</FilesMatch>
UseCanonicalName Off
VirtualDocumentRoot /var/www/hosts/%-4.0.%-3.0/%-5+
<Directory "/var/www">
AllowOverride All
Options -Indexes +FollowSymLinks
Require all granted
</Directory>
ProxyPassMatch ^/(.*\.php(/.*)?)$ "fcgi://127.0.0.1:9000/var/www/hosts/%-4.0.%-3.0/%-5+"
</VirtualHost>
<VirtualHost *:443>
ServerName paul.test
ServerAlias *.paul.test
<FilesMatch \.php$>
Require all granted
SetHandler proxy:fcgi://127.0.0.1:9000
</FilesMatch>
UseCanonicalName Off
VirtualDocumentRoot /var/www/hosts/%-4.0.%-3.0/%-5+
SSLEngine on
SSLCipherSuite AES256+EECDH:AES256+EDH
SSLProtocol All -SSLv2 -SSLv3
SSLHonorCipherOrder On
SSLCompression off
SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
<Directory "/var/www">
AllowOverride All
Options -Indexes +FollowSymLinks
Require all granted
</Directory>
ProxyPassMatch ^/(.*\.php(/.*)?)$ "fcgi://127.0.0.1:9000/var/www/hosts/%-4.0.%-3.0/%-5+"
</VirtualHost>
PHP FPM
Теперь проблема в том, что когда я вызываю PHP-файл: тогда я вижу “Файл не найден.” в веб-браузере.
pool.d/www.conf
Примечание: для удобства чтения я пропустил все комментарии
[www]
user = www-data
group = www-data
listen = 127.0.0.1:9000
listen.owner = www-data
listen.group = www-data
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 5
listen.allowed_clients = 127.0.0.1
Журналы ошибок
Журнал ошибок PHP-FPM говорит, что он работает нормально:
[24-Dec-2020 12:16:06] NOTICE: fpm is running, pid 26532
[24-Dec-2020 12:16:06] NOTICE: ready to handle connections
[24-Dec-2020 12:16:06] NOTICE: systemd monitor interval set to 10000ms
Журнал ошибок Apache показывает ошибку:
[Thu Dec 24 12:44:38.779511 2020] [proxy_fcgi:error] [pid 26424:tid 140510559713024] [client ::1:57178] AH01071: Got error 'Primary script unknown'
Как исправить / исследовать?
Для начала, я нахожу сообщение об ошибке “Файл не найден.” очень неясным. Кто не нашел какой файл? Это помогло бы мне и другим, кто столкнется с этой ошибкой в будущем, объяснить, кто вызывает эту ошибку и что это на самом деле означает.
Мой вывод на данный момент таков, что сообщение об ошибке выдается Apache и означает, что он не может найти процесс PHP-FPM. Это верно?
Как мне дальше исследовать и исправить это?
Правка: Добавляю свою настройку Apache и PHP-FPM.
Правка / важное примечание
В процессе улучшения этого поста и исследования проблемы я выяснил, что базовая настройка Apache и PHP-FPM работает нормально.
Проблема, по-видимому, вызвана следующим оператором:
ProxyPassMatch ^/(.*\.php(/.*)?)$ "fcgi://127.0.0.1:9000/var/www/hosts/%-4.0.%-3.0/%-5+"
Этот оператор работал нормально на предыдущей настройке (с Centos), но сейчас не работает. Когда я заменяю этот оператор на статический путь к корню документа, он работает нормально.
Я буду исследовать дальше, но если кто-то знает, как это исправить, пожалуйста, дайте знать.
После дальнейшего расследования я выяснил, что моя ProxyPassMatch
инструкция вызвала ошибку. А затем я нашел пост на StackOverflow, в котором говорилось, что весь оператор ProxyPassMatch не следует использовать.
Просто SetHandler proxy:fcgi://127.0.0.1:9000
(который уже был в моем vhost) заставляет PHP работать.
Поскольку это первый результат, который Google дал мне, когда я искал “apache php-fpm file not found”, я хотел бы добавить свой ответ здесь.
Если корень документа, доступный для Apache, отличается от корня документа, доступного для PHP-FPM
В моем случае корень документа, доступный для Apache, был /data/.../wwwroot
, а корень документа для PHP-FPM (который работает в контейнере) был /var/www/html
.
Исправление заключалось в том, чтобы настроить DOCUMENT_ROOT
и SCRIPT_FILENAME
с помощью ProxyFCGISetEnvIf
:
Define container_root "/var/www/html"
<FilesMatch "\.php$">
<If "-f %{REQUEST_FILENAME}">
SetHandler "proxy:fcgi://127.0.0.1:9000"
ProxyFCGISetEnvIf "true" DOCUMENT_ROOT "${container_root}"
ProxyFCGISetEnvIf "true" SCRIPT_FILENAME "%{HANDLER}${container_root}%{reqenv:SCRIPT_NAME}"
</If>
</FilesMatch>
UnDefine container_root
(Примечание о различных синтаксисах доступа к переменным: каждый синтаксис предназначен для переменных из разных источников. ${}
используется для того, что определено с помощью Define
или с помощью аргумента командной строки -D
; %{}
используется для переменных, определенных Apache; а %{reqenv:}
– это вызов функции для доступа к внутренней переменной окружения.)
Вы можете отладить эти переменные, добавив следующие строки в конце раздела FilesMatch
:
Header always set X-HANDLER "expr=%{HANDLER}"
Header always set X-DOCUMENT_ROOT "expr=%{reqenv:DOCUMENT_ROOT}"
Header always set X-SCRIPT_FILENAME "expr=%{reqenv:SCRIPT_FILENAME}"
Header always set X-SCRIPT_NAME "expr=%{reqenv:SCRIPT_NAME}"
После этого вы должны увидеть их в заголовках ответа.
Просто добавлю немного информации на случай, если кто-то захочет исправить проблему, но для Symfony ответ от @MichaelK
верный.
Просто Define container_root "/var/www/html/public"
должен указывать на публичную папку symfony внутри контейнера.
Надеюсь, это поможет кому-то.
Ответ или решение
Настройка Apache с PHP-FPM: ошибка "Файл не найден"
При настройке сервера Apache с поддержкой PHP-FPM на WSL2 (Windows Subsystem for Linux) с использованием Ansible, многие пользователи сталкиваются с ошибкой "Файл не найден" при попытке доступа к PHP-файлам. Данная проблема может быть несколько запутанной, поскольку сообщение об ошибке не всегда однозначно указывает на источник проблемы.
Основные аспекты конфигурации
1. Виртуальный хост Apache
Ваша конфигурация виртуального хоста выглядит следующим образом:
<DirectoryIndex index.php index.html>
<VirtualHost *:80>
ServerName paul.test
ServerAlias *.paul.test
<FilesMatch \.php$>
Require all granted
SetHandler proxy:fcgi://127.0.0.1:9000
</FilesMatch>
UseCanonicalName Off
VirtualDocumentRoot /var/www/hosts/%-4.0.%-3.0/%-5+
<Directory "/var/www">
AllowOverride All
Options -Indexes +FollowSymLinks
Require all granted
</Directory>
ProxyPassMatch ^/(.*\.php(/.*)?)$ "fcgi://127.0.0.1:9000/var/www/hosts/%-4.0.%-3.0/%-5+"
</VirtualHost>
2. Конфигурация PHP-FPM
Конфигурация pool.d/www.conf
фрагментирована следующим образом:
[www]
user = www-data
group = www-data
listen = 127.0.0.1:9000
listen.owner = www-data
listen.group = www-data
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 5
listen.allowed_clients = 127.0.0.1
Анализ проблемы
Ошибка, записанная в логах Apache:
[proxy_fcgi:error] [pid 26424:tid 140510559713024] [client ::1:57178] AH01071: Got error 'Primary script unknown'
указывает на то, что Apache не может найти скрипт. Это связано с тем, что конфигурация ProxyPassMatch может не соответствовать фактическому пути PHP-скрипта, к которому пытается обратиться Apache.
Решение проблемы
1. Упрощение настройки
Как было выяснено, использование директивы ProxyPassMatch
может не быть необходимым в вашем случае. Достаточно установить SetHandler
для обработки PHP-скриптов:
<FilesMatch "\.php$">
Require all granted
SetHandler proxy:fcgi://127.0.0.1:9000
</FilesMatch>
2. Убедитесь, что пути соответствуют
Если ваш Apache-корень и корень PHP-FPM находятся в разных местах, необходимо явно задать их с помощью переменных окружения. Например, используйте ProxyFCGISetEnvIf
для определения корневых директорий:
Define container_root "/var/www/html"
<FilesMatch "\.php$">
<If "-f %{REQUEST_FILENAME}">
SetHandler "proxy:fcgi://127.0.0.1:9000"
ProxyFCGISetEnvIf "true" DOCUMENT_ROOT "${container_root}"
ProxyFCGISetEnvIf "true" SCRIPT_FILENAME "%{HANDLER}${container_root}%{reqenv:SCRIPT_NAME}"
</If>
</FilesMatch>
UnDefine container_root
3. Отладка переменных
Добавьте следующие заголовки, чтобы видеть значения переменных при отладке:
Header always set X-HANDLER "expr=%{HANDLER}"
Header always set X-DOCUMENT_ROOT "expr=%{reqenv:DOCUMENT_ROOT}"
Header always set X-SCRIPT_FILENAME "expr=%{reqenv:SCRIPT_FILENAME}"
Header always set X-SCRIPT_NAME "expr=%{reqenv:SCRIPT_NAME}"
Это поможет вам удостовериться в правильности настроек и путей.
Заключение
Как показывает практика, проблема "Файл не найден" при настройке Apache с PHP-FPM часто возникает из-за неверной конфигурации путей к файлам. Упрощая обработку PHP и обеспечивая соответствие между корнями, вы сможете устранить эту проблему. Ключом к успешной настройке является внимание к деталям в конфигурации и открытие для отладки значений переменных. Если возникают дополнительные трудности, рассмотрите возможность использования статического пути для начала, чтобы подтвердить работоспособность основного сценария.