Назад | Перейти на главную страницу

Apache 2.4 + PHP-FPM + ProxyPassMatch

Недавно я установил 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 ...>

 ...

 # This is to forward all PHP to php-fpm.
 <FilesMatch \.php$>
   SetHandler "proxy:unix:/path/to/socket.sock|fcgi://unique-domain-name-string/"
 </FilesMatch>

 # Set some proxy properties (the string "unique-domain-name-string" should match
 # the one set in the FilesMatch directive.
 <Proxy fcgi://unique-domain-name-string>
   ProxySet connectiontimeout=5 timeout=240
 </Proxy>

 # If the php file doesn't exist, disable the proxy handler.
 # This will allow .htaccess rewrite rules to work and 
 # the client will see the default 404 page of Apache
 RewriteCond %{REQUEST_FILENAME} \.php$
 RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} !-f
 RewriteRule (.*) - [H=text/html]

</VirtualHost>

Согласно документации Apache, для параметра прокси SetHandler требуется Apache HTTP Server 2.4.10.

Я надеюсь, что это решение вам тоже поможет.

Вчера я тоже столкнулся с этой проблемой - Apache 2.4 переехал из Debian / экспериментальный в Debian / нестабильный заставляя меня заниматься этим новым материалом; не на наших производственных серверах конечно;).

Прочитав миллионы сайтов, документацию 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>

Вышеупомянутый vhost отлично работает с .htaccess в корне, например:

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^(.*)$ index.php [QSA,L]
</IfModule>

Я не совсем понимаю, что вы имеете в виду под URL rewriting inside a subdirectory хотя (я переписываю только на корневой index.php).


(О, и вам нужно убедиться, что Xdebug не конфликтует с FPM в вашей системе, они сразу же хотят использовать одни и те же порты.)

Все, что вам нужно сделать, это установить:

 ProxyErrorOverride on

И не забудьте настроить страницу клиента:

ErrorDocument 404 /path/to/error_page_file    

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

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} ^/((.*\.php)(/.*)?)$
RewriteCond %2 -f
RewriteRule . fcgi://127.0.0.1:9000/%1 [L,P]
RewriteOptions Inherit

Я пытался сделать что-то подобное без перезаписи («Если» и тому подобное), но ничего не получалось.

РЕДАКТИРОВАТЬ: Обратите внимание, что если вы реализуете это как поставщик общего хостинга, это может быть проблемой безопасности. Это позволит пользователям передавать сценарии PHP на произвольный прокси-сервер fcgi. Если бы у вас был отдельный пул для каждого пользователя, это позволило бы повысить привилегии атак.

Еще одно решение (требуется Apache> = 2.4.10) - Внутри vhost:

# define worker
<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 к На, имейте в виду, что это действительно плохая идея. Использование этой директивы не вызывает никаких проблем. Например, любое приложение PHP, отправляющее код HTTP, такой как 503, приведет к неожиданному результату. Обработчик ошибок по умолчанию будет задействован в любых случаях, а для приложений PHP, которые предоставляют API, это действительно плохое поведение.

Лучший способ решить эту проблему - включить журналы отладки для 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

Но ТОЛЬКО, если пул на этом порту находится в режиме chrooted.

Я не уверен, связана ли проблема, но я нашел здесь частичное рабочее решение:

https://stackoverflow.com/questions/44054617/mod-rewrite-in-2-4-25-triggering-fcgi-primary-script-unknown-error-in-php-fpm

Кажется, трюк в том, чтобы добавить? char в .htaccess RewriteRule, например, используя:

RewriteRule ^(.*)$ index.php?/$1 [L,NS]

вместо того:

RewriteRule ^(.*)$ index.php/$1 [L,NS]

Источником проблемы, похоже, является изменение mod_rewrite в Apache 2.4.25. Я использовал уровень журнала Apache trace1 для наблюдения за "циклом", который передает $ 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

просто вставьте

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). После отслеживания журнала 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, прокси, а также с 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]

; The address on which to accept FastCGI requests.
; Valid syntaxes are:
;   'ip.add.re.ss:port'    - to listen on a TCP socket to a specific address on
;                            a specific port;
;   'port'                 - to listen on a TCP socket to all addresses on a
;                            specific port;
;   '/path/to/unix/socket' - to listen on a unix socket.
; Note: This value is mandatory.
listen = 127.0.0.1:9000
listen = /run/php-fcgi.sock

sudo ll /run/php-fcgi.sock

Должен дать srw-rw-rw-.

Или как настроить на Debian / Ubuntu

Руководство:

источник: https://emi.is/?page=articles&article=php-7-installation-and-configuration-for-apache-2.4-using-php-fpm-(debian,-repository)


sudo apt purge 'php*' or 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 in 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

скопируйте это в txt файл:

/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 admin@example.com
    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>
    #headers for security man in the middle attack find how to enable this mod in 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 admin@example.com
        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>
    # Log file locations
    #LogLevel info ssl:warn
    LogLevel debug
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

    # modern configuration
    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>
    #Stapling OCSP for Let's Encrypt certs.
    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