Вопрос или проблема
Недавно я установил Apache 2.4 на свой локальный компьютер вместе с PHP 5.4.8, используя PHP-FPM.
Всё прошло довольно гладко (после некоторого времени…) но всё же есть странная ошибка:
Я настроил Apache для PHP-FPM следующим образом:
<VirtualHost *:80>
ServerName localhost
DocumentRoot "/Users/apfelbox/WebServer"
ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/Users/apfelbox/WebServer/$1
</VirtualHost>
Это работает, например, если я обращаюсь к http://localhost/info.php
, я получаю правильный phpinfo()
(это просто тестовый файл).
Однако, если я обращаюсь к директории, я получаю 404 с телом File not found.
и в журнале ошибок:
[Tue Nov 20 21:27:25.191625 2012] [proxy_fcgi:error] [pid 28997] [client ::1:57204] AH01071: Got error 'Primary script unknown\n'
Обновление
Теперь я попробовал сделать проксирование с помощью mod_rewrite:
<VirtualHost *:80>
ServerName localhost
DocumentRoot "/Users/apfelbox/WebServer"
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/Users/apfelbox/WebServer/$1 [L,P]
</VirtualHost>
Но проблема в том, что всегда происходит перенаправление, потому что при обращении на http://localhost/
автоматически запрашивается http://localhost/index.php
, из-за
DirectoryIndex index.php index.html
Обновление 2
Хорошо, так что я подумал, “может быть, сначала проверить, есть ли файл, чтобы передать его прокси:
<VirtualHost *:80>
ServerName localhost
DocumentRoot "/Users/apfelbox/WebServer"
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/Users/apfelbox/WebServer/$1 [L,P]
</VirtualHost>
Теперь полное переписывание больше не работает…
Обновление 3
Теперь у меня есть такое решение:
<VirtualHost *:80>
ServerName localhost
DocumentRoot "/Users/apfelbox/WebServer"
RewriteEngine on
RewriteCond /Users/apfelbox/WebServer/%{REQUEST_FILENAME} -f
RewriteRule ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/Users/apfelbox/WebServer/$1 [L,P]
</VirtualHost>
Сначала проверьте, есть ли файл для передачи в PHP-FPM (с полным и абсолютным путем), а затем выполняйте перенаправление.
Это не работает при использовании переадресации URL внутри поддиректории, а также не работает для URL, таких как http://localhost/index.php/test/
. Так что возвращаемся к началу.
Есть идеи?
После часов поиска и чтения документации Apache я нашел решение, которое позволяет использовать пул и также позволяет директиве Rewrite в .htaccess работать даже тогда, когда URL содержит файлы .php.
<VirtualHost ...>
...
# Это для перенаправления всех PHP в php-fpm.
<FilesMatch \.php$>
SetHandler "proxy:unix:/path/to/socket.sock|fcgi://unique-domain-name-string/"
</FilesMatch>
# Установите некоторые свойства прокси (строка "unique-domain-name-string" должна соответствовать
# той, что установлена в директиве FilesMatch.
<Proxy fcgi://unique-domain-name-string>
ProxySet connectiontimeout=5 timeout=240
</Proxy>
# Если php-файл не существует, отключите обработчик прокси.
# Это позволит работать правилам переписывания в .htaccess и
# клиент увидит стандартную страницу 404 Apache
RewriteCond %{REQUEST_FILENAME} \.php$
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} !-f
RewriteRule (.*) - [H=text/html]
</VirtualHost>
Согласно документации Apache, параметр SetHandler proxy требует Apache HTTP Server 2.4.10.
Надеюсь, это решение поможет и вам.
Вчера я столкнулся с этой проблемой — Apache 2.4 перешел из Debian/experimental в Debian/unstable, заставив меня разобраться с этими новшествами; конечно, не на наших производственных серверах ;).
После прочтения огромного количества сайтов, документации Apache, отчетов об ошибках и анализа отладочного вывода в журнале ошибок я наконец-то заставил это работать. Нет, еще нет поддержки FPM с сокетами. Конфигурация Debian по умолчанию уже некоторое время использует сокеты, поэтому пользователи Debian тоже должны изменить это.
Вот что работает для сайта CakePHP и PHPMyAdmin (последнему нужна некоторая настройка, если вы используете пакеты Debian), так что я могу подтвердить, что mod_rewrite
все еще работает ожидаемо для выполнения сложного переписывания URL.
Обратите внимание на DirectoryIndex index.php
, это может быть причиной того, почему ни одна из ваших конфигураций не работала для “папок” (по крайней мере, это то, что не работало здесь).
Я все еще получаю File not found
для директорий, но только если нет индексного файла, который можно проанализировать. Хотел бы избавиться от этого тоже, но это не так критично на данный момент.
<VirtualHost *:80>
ServerName site.localhost
DocumentRoot /your/site/webroot
<Directory />
Options FollowSymlinks
DirectoryIndex index.php
AllowOverride All
Require all granted
</Directory>
<LocationMatch "^(.*\.php)$">
ProxyPass fcgi://127.0.0.1:9000/your/site/webroot
</LocationMatch>
LogLevel debug
ErrorLog /your/site/logs/error.log
CustomLog /your/site/logs/access.log combined
</VirtualHost>
Вышеуказанный виртуальный хост отлично работает с файлом .htaccess в корне, как этот:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [QSA,L]
</IfModule>
Я не совсем понимаю, что вы имеете в виду под переадресацией URL внутри поддиректории
(я только делаю переписывание на корневой index.php).
(О, и вам нужно убедиться, что Xdebug не конфликтует с FPM на вашей системе, изначально они хотят использовать те же порты.)
Все, что вам нужно сделать, это установить:
ProxyErrorOverride on
И не забудьте установить пользовательскую страницу при помощи:
ErrorDocument 404 /path/to/error_page_file
Еще одно решение (требует Apache >= 2.4.10) — внутри файла виртхоста:
# определить воркер
<Proxy "unix:/var/run/php5-fpm-wp.bbox.nuxwin.com.sock|fcgi://domain.tld" retry=0>
ProxySet connectiontimeout=5 timeout=7200
</Proxy>
<If "%{REQUEST_FILENAME} =~ /\.php$/ && -f %{REQUEST_FILENAME}">
SetEnvIfNoCase ^Authorization$ "(.+)" HTTP_AUTHORIZATION=$1
SetHandler proxy:fcgi://domain.tld
</If>
Итак, здесь обработчик fcgi для PHP будет установлен только в том случае, если файл существует и его имя соответствует расширению файла PHP.
Кстати: Для тех, кто захочет установить ProxyErrorOverride на On, учтите, что это действительно плохая идея. Использование этой директивы может привести к проблемам. Например, любое PHP-приложение, отправляющее HTTP-коды, такие как 503, может привести к неожиданным результатам. Стандартный обработчик ошибок будет задействован в любых случаях, и для PHP-приложений, предоставляющих API, это действительно плохое поведение.
Вот что у меня есть. Кажется, работает нормально. Я поместил Drupal в поддиректорию, её переписывания работают, индексы директории работают, и PATH_INFO тоже работает.
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} ^/((.*\.php)(/.*)?)$
RewriteCond %2 -f
RewriteRule . fcgi://127.0.0.1:9000/%1 [L,P]
RewriteOptions Inherit
Я пытался сделать что-то подобное без переписываний (“If” и другие), но не смог ничего добиться.
ПРИМЕЧАНИЕ: Учтите, если вы примените это как провайдер хостинга, это может стать проблемой безопасности. Это позволит пользователям передавать PHP-скрипты на произвольный fcgi-прокси. Если у вас будет отдельный пул для каждого пользователя, это позволит выполнять атаки повышения привилегий.
Лучший способ решить это — включить отладочные логи для mod_proxy и mod_rewrite и php-fpm. В Apache 2.4 теперь можно включить отладочные логи только для определенных модулей. http://httpd.apache.org/docs/current/mod/core.html#loglevel Настройка по модулю и по каталогу доступна в Apache HTTP Server 2.3.6 и выше
Может быть, у вас двойной слэш в директориях?
Вот что я использую, и это работает:
<LocationMatch ^(.*\.php)$>
ProxyPass fcgi://127.0.0.1:9000/home/DOMAINUSER/public_html$1
</LocationMatch>
Одну вещь, которую я обнаружил, столкнувшись с этой проблемой, — это то, что если вы используете комбинацию:
chroot = /path/to/site
chdir = /
В вашей конфигурации пула fpm, не передавайте полный путь в директиву ProxyPass
.
ProxyPass fcgi://127.0.0.1:9020/$1
Но -Только- если пул на этом порту находится в chroot.
Я не уверен, связана ли проблема, но частично работающее решение я нашел здесь:
Фишка заключается в добавлении символа ? в RewriteRule в .htaccess, например, используя:
RewriteRule ^(.*)$ index.php?/$1 [L,NS]
вместо:
RewriteRule ^(.*)$ index.php/$1 [L,NS]
Источник проблемы, похоже, заключается в изменении в mod_rewrite Apache 2.4.25. Я использовал Apache trace1 log level для наблюдения за “циклом”, который передает $1 в php-fpm после того, как index.php/$1 был передан. $1 генерирует ошибку “AH01071: Got error ‘Primary script unknown\n'”.
Надеюсь, эта небольшая часть информации поможет кому-то решить их проблемы.
Немного измененная версия ответа @FrancescoA, которая не требует mod_rewrite
<IfModule proxy_fcgi_module>
<FilesMatch \.php$>
<If "-f '%{REQUEST_FILENAME}'">
SetHandler "proxy:unix:/path/to/socket.sock|fcgi://unique-domain-name-string/"
</If>
</FilesMatch>
<Proxy fcgi://unique-domain-name-string>
ProxySet connectiontimeout=5 timeout=240
</Proxy>
</IfModule>
Linode имеет отличный учебник на эту тему
В основном вы настраиваете обработчик для всего сервера, который будет ловить любые php-скрипты и передавать их в fast-cgi.
У меня тоже была ошибка после переключения на php-fpm + apache 2.4.6 для инстансов drupal
но я использую mpm event mod
просто добавление
DirectoryIndex index.php
сработало для меня
тогда мои настройки Vhost выглядят следующим образом
<VirtualHost *:8080>
ServerAdmin webmaster@localhost
ServerName sever.com
DocumentRoot /var/www/html/webroot
ErrorLog logs/web-error_log
CustomLog logs/web-access_log common
<IfModule mpm_event_module>
ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/var/www/html/webroot/$1
</IfModule>
<Directory /var/www/html/webroot>
Options FollowSymlinks
DirectoryIndex index.php
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
спасибо
нет необходимости пересматривать файл .htaccess Drupal по умолчанию
Я столкнулся с аналогичной проблемой на своем сервере (centos 7.3.16 docker). После отслеживания логов php-fpm я обнаружил отсутствие системной библиотеки.
WARNING: [pool www] child 15081 said into stderr: "php-fpm: pool www: symbol lookup error: /lib64/libnsssysinit.so: undefined symbol: PR_GetEnvSecure"
затем я переустановил nspr, и это сработало. Если вы не можете найти решение после попытки разных методов, возможно, стоит попробовать это.
yum -y install/reinstall nspr
Это работает с WordPress 5.1.1 и новее вместе с PHP 7.3, FastCGI, proxy, а также MariaDB/MySQL. Проверено дважды на моих серверах. Работает как часы.
Сначала на CentOS/Fedora/Red Hat
sudo yum remove php*
sudo yum --enablerepo=extras install epel-release
sudo yum install php-fpm php-mysql php-gd php-imap php-mbstring
sudo grep -E '(proxy.so|fcgi)' /etc/httpd/conf.modules.d/00-proxy.conf
sudo mv /etc/httpd/conf.d/php.conf /etc/httpd/conf.d/php.conf_bak
Отредактируйте этот файл:
sudo nano /etc/php-fpm.d/www.conf
Вставьте это:
[www]
; Адрес, по которому принимать запросы FastCGI.
; Допустимые синтаксисы:
; 'ip.add.re.ss:port' - слушать на TCP-сокете на определенном адресе на
; определенном порте;
; 'port' - слушать на TCP-сокете на всех адресах на
; определенном порте;
; '/path/to/unix/socket' - слушать на unix-сокете.
; Примечание: это значение обязательно.
listen = 127.0.0.1:9000
listen = /run/php-fcgi.sock
sudo ll /run/php-fcgi.sock
Должно выдать srw-rw-rw-.
Или как настроить на Debian/Ubuntu
Учебник:
sudo apt purge 'php*' или sudo apt-get purge 'php*'
sudo add-apt-repository ppa:ondrej/php
sudo apt-get update
sudo apt install php7.3 php7.3-fpm php-mysql php-mbstring php-gd php-imap libapache2-mod-security2 modsecurity-crs
systemctl status php7.3-fpm
systemctl stop php7.3-fpm.service
sudo a2dismod php7.0 php7.1 php7.2 mpm_event mpm_worker
sudo a2enmod mpm_prefork
sudo a2enmod php7.3
sudo systemctl restart apache2 (httpd в CentOS)
Проблема в том, что php 7.3 из репозитория Ondrej работает только с модулем mpm_prefork. У него есть git-репозиторий, так что вы можете найти его в сети и спросить его, сделает ли он php 7.3 для mpm_worker и mpm_event.
Остальная часть конфигурации для дистрибутивов семейства Debian приведена ниже:
sudo apt --assume-yes install php7.3-fpm
sudo systemctl stop php7.3-fpm.service
sudo rm /var/log/php7.0-fpm.log
sudo mkdir /var/log/php7.3-fpm/
sudo touch /var/log/php7.3-fpm/error.log
sudo mkdir /var/log/php7.3/
sudo touch /var/log/php7.3/error.log
sudo mkdir /var/tmp/php7.3/
sudo > /etc/php/7.3/fpm/php.ini
sudo > /etc/php/7.3/fpm/php-fpm.conf
sudo rm /etc/php/7.3/fpm/pool.d/www.conf
sudo touch /etc/php/7.3/fpm/pool.d/example.com.conf
sudo useradd --comment "PHP" --shell "/usr/sbin/nologin" --system --user-group php
sudo nano /etc/php/7.3/fpm/php.ini
вставьте
[PHP]
date.timezone = Europe/Prague
display_errors = Off
error_log = /var/log/php7.3/error.log
error_reporting = 32767
log_errors = On
register_argc_argv = Off
session.gc_probability = 0
short_open_tag = Off
upload_tmp_dir = /var/tmp/php7.3/
sudo nano /etc/php/7.3/fpm/php-fpm.conf
вставьте
[global]
error_log = /var/log/php7.3-fpm/error.log
include = /etc/php/7.3/fpm/pool.d/*.conf
sudo nano /etc/php/7.3/fpm/pool.d/example.com.conf
вставьте
[example.com]
group = php
listen = 127.0.0.1:9000
pm = ondemand
pm.max_children = 5
pm.max_requests = 200
pm.process_idle_timeout = 10s
user = php
sudo nano /etc/logrotate.d/php7.3-fpm
скопируйте это в текстовый файл:
/var/log/php7.3-fpm.log {
rotate 12
weekly
missingok
notifempty
compress
delaycompress
postrotate
/usr/lib/php/php7.3-fpm-reopenlogs
endscript
}
удалите его и затем вставьте это вместо предыдущего:
/var/log/php7.3/*.log /var/log/php7.3-fpm/*.log
{
copytruncate
maxage 365
missingok
monthly
notifempty
rotate 12
}
Добавьте директиву
sudo nano /etc/apache2/sites-available/example.com.conf
<VirtualHost *:80>
ServerName www.example.com
ServerAlias example.com
ServerAdmin [email protected]
DocumentRoot /var/www/html/example.com/public_html
DirectoryIndex index.php index.htm index.html index.xht index.xhtml
LogLevel info warn
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
<FilesMatch "^\.ht">
Require all denied
</FilesMatch>
<files readme.html>
order allow,deny
deny from all
</files>
RewriteEngine on
RewriteCond %{SERVER_NAME} =example.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/var/www/html/example.com/public_html
<Directory /var/www/html/example.com/public_html>
Options Indexes FollowSymLinks Includes IncludesNOEXEC SymLinksIfOwnerMatch
AllowOverride None
</Directory>
</VirtualHost>
Затем активируйте сайт:
sudo a2ensite /etc/apache2/sites-available/example.com.conf
Далее отредактируйте SSL сайт (в данном случае certbot от Let’s Encrypt был установлен и настроен предварительно в начале настройки SSL сертификата).
sudo nano /etc/apache2/sites-available/example.com-le-ssl.conf
<IfModule mod_ssl.c>
# заголовки для защиты от атак Man-in-the-Middle, найдите, как включить этот модуль в Google
LoadModule headers_module modules/mod_headers.so
<VirtualHost *:443>
Header always set Strict-Transport-Security "max-age=15768000"
SSLEngine On
ServerName example.com
ServerAdmin [email protected]
DocumentRoot /var/www/html/example.com/public_html
<Directory /var/www/html/example.com/public_html>
Options Indexes FollowSymLinks Includes IncludesNOEXEC SymLinksIfOwnerMatch
AllowOverride All
Require all granted
DirectoryIndex index.php
RewriteEngine On
<FilesMatch ^/(.*\.php(/.*)?)$>
SetHandler "fcgi://example.com:9000/var/www/html/example.com/public_html"
</FilesMatch>
</Directory>
# расположение логов
#LogLevel info ssl:warn
LogLevel debug
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
# современная конфигурация
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
#SSLCipherSuite HIGH:!aNULL:!MD5
SSLCipherSuite ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM$
SSLHonorCipherOrder on
SSLCompression off
SSLSessionTickets off
<FilesMatch "^\.ht">
Require all denied
</FilesMatch>
<files readme.html>
order allow,deny
deny from all
</files>
</VirtualHost>
#Степлинг OCSP для сертификатов Let's Encrypt.
SSLUseStapling on
SSLStaplingResponderTimeout 5
SSLStaplingReturnResponderErrors off
SSLStaplingCache shmcb:/var/run/ocsp(128000)
</IfModule>
sudo a2enmod proxy proxy_fcgi setenvif
sudo systemctl reload apache2.service
sudo chown --recursive root:adm /etc/php/
sudo chmod --recursive 0770 /etc/php/
sudo chown --recursive php:adm /var/log/php7.3/
sudo chown --recursive php:adm /var/log/php7.3-fpm/
sudo chmod --recursive 0770 /var/log/php7.3/
sudo chmod --recursive 0770 /var/log/php7.3-fpm/
sudo chown --recursive php:php /var/tmp/php7.3/
sudo chmod --recursive 0770 /var/tmp/php7.3/
sudo a2enconf php7.3-fpm
sudo systemctl enable php7.3-fpm.service
sudo systemctl start php7.3-fpm.service
Не забудьте добавить порт 9000 в файрвол на Debian/Ubuntu
sudo ufw allow 9000/tcp
sudo ufw status
На CentoOS / Fedora/ Red Hat
sudo firewall-cmd --zone=public --add-port=9000/tcp --permanent
sudo firewall-cmd --reload
sudo firewall-cmd --list-all
sudo firewall-cmd --state
Ответ или решение
Настройка связки Apache 2.4, PHP-FPM и ProxyPassMatch может быть довольно сложной задачей, особенно если вы сталкиваетесь с ошибками 404 и сообщением "Primary script unknown". Для решения этой проблемы необходимо глубоко понять, как взаимодействуют между собой эти компоненты.
Теория
Apache HTTP Server 2.4 предоставляет мощный модуль для обратных прокси-серверов под названием mod_proxy, который в сочетании с mpm_event позволяет эффективно интегрировать PHP-FPM. PHP-FPM, в свою очередь, является процессом FastCGI, позволяющим PHP обрабатывать запросы через верхний уровень абстракции серверов.
ProxyPassMatch — это директива Apache, используемая для сопоставления URL с шаблоном и последующей переадресации запросов на указанный сервер FastCGI. Ошибка "Primary script unknown" часто появляется из-за того, что Apache не может корректно найти файл скрипта PHP, который необходимо обработать PHP-FPM.
Пример
Рассмотрим возможное решение проблемы на вашем примере. Вы указывали конфигурацию VirtualHost и использовали ProxyPassMatch следующим образом:
<VirtualHost *:80>
ServerName localhost
DocumentRoot "/Users/apfelbox/WebServer"
ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/Users/apfelbox/WebServer/$1
</VirtualHost>
Данное правило проксирует запросы к .php файлам на PHP-FPM процесс, прослушивающий на localhost:9000. Однако в случае, когда вы сталкиваетесь с ошибкой "Primary script unknown", возможно неправильно сформирован путь к файловой системе или есть проблемы с разрешением доступа к PHP-FPM.
Применение
-
Проверьте файловую структуру и права доступа:
Убедитесь, что файловая система соответствует пути, указанному в ProxyPassMatch, и что веб-сервер Apache имеет достаточно прав для доступа к файлам и папкам. -
Используйте полный путь до сокета:
Если вы используете Unix-сокеты для PHP-FPM, замените "fcgi://127.0.0.1:9000" на путь сокета, например "unix:/path/to/socket.sock|fcgi://". -
Настройте FilesMatch и SetHandler:
Для подключения с PHP-FPM через сокеты следует настроить FilesMatch:<FilesMatch \.php$> SetHandler "proxy:unix:/path/to/socket.sock|fcgi://unique-domain-name-string/" </FilesMatch>
-
Дополнительные проверки через mod_rewrite:
Перенастройте правила mod_rewrite, чтобы сначала проверять существование файлов:RewriteEngine On RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} -f RewriteRule ^(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000%{REQUEST_URI} [L,P]
-
Включите журнал модулей:
Используйте директивы LogLevel, чтобы включить подробное логирование для mod_proxy и mod_rewrite, что поможет диагностировать ошибки. -
Проверка и настройка PHP-FPM:
Убедитесь, что в конфигурации pool PHP-FPM для каждого пользователя указаны правильные значения chroot и listen:chroot = /path/to/application/root listen = /var/run/php-fpm.sock
Если все рекомендации, включая предоставление более подробных журналов и проверки конфигурации, не помогли, возможно, следует проанализировать сетевые настройки и исключить присутствие сетевых ограничений или конфликтов порта.
Этот методический подход обеспечит стабильную работу связки Apache 2.4, PHP-FPM и ProxyPassMatch и позволит избежать распространенных ошибок конфигурации. Важно соблюдать последовательность действий и тщательно проверять права доступа и корректность указанных путей.