Apache 2.4 + PHP-FPM + ProxyPassMatch

31

Я недавно установил 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/ So обратно на квадрат.


Любые идеи?

apfelbox
источник

Ответы:

34

После нескольких часов поиска и прочтения документации по 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 требуется HTTP-сервер Apache 2.4.10.

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

FrancescoA
источник
2
Это, безусловно, ответ на 2015 год, все остальное здесь дерьмо для современной установки (скажем, стабильная версия Debian)
Дмитрий Д.Б.
1
Я довольно долго бился головой об стену от этой же проблемы, и у меня очень похожая установка, как у вас. Не могли бы вы опубликовать свои директивы .htaccess Rewrite? Из того, что я понимаю, все в этом ответе - только то, что у вас есть в вашем файле httpd.d / site.conf.
Дэвид W
1
На данный момент использование этого RewriteRule кажется довольно опасным, поскольку он может представлять config.php файлы в обычном виде, если они находятся в каталогах с псевдонимами и, следовательно, не существуют в% {DOCUMENT_ROOT} /% {REQUEST_URI}.
Зулакис,
1
Удивительные 9 строк кода. Это Святой Грааль и единственное, что работает на 100% для меня. Просто примечание: если вы переключаетесь с решения, использующего LocationMatch, вам не нужно добавлять абсолютный путь к файлу в URL fcgi. Включите прокси-сервер и перепишите запись в apache, чтобы следить за этим.
Фил
1
+1, потому что этот пост, в отличие от любого другого ресурса, который я видел, помог мне понять, что должна представлять «unique-domain-name-string».
три
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 в вашей системе, из коробки они хотят использовать те же порты.)

Alex
источник
Это хорошее решение, но, к сожалению, этот подход не работает, когда URL-адреса, содержащие .php, необходимо переписать, например, для многосайтового WordPress. /ms_blog_1/wp-admin/load-scripts.php?blah=blah
Фил
Для меня просто добавление переопределения DirectoryIndex index.htmlв рассматриваемом vhost исправило это. Если да DirectoryIndex index.php, то, похоже, другие PHP-файлы в итоге выдают ошибку «Файл не найден» и «Основной сценарий неизвестен». В моем случае у меня есть, index.htmlно файл php test.php.
geerlingguy
4

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

 ProxyErrorOverride on

И не забудьте установить страницу клиента с помощью:

ErrorDocument 404 /path/to/error_page_file    
Шики чжун
источник
2

Это то, что у меня есть. Кажется, работает нормально. Я поместил 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-прокси. Если бы у вас был отдельный пул для каждого пользователя, это позволило бы атаковать с повышением привилегий.

RockinRoel
источник
2

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

Nuxwin
источник
К сожалению, все еще возникла ошибка «AH01071: Ошибка« Основной сценарий неизвестен \ n »» при использовании этого решения.
Klor
1

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

Одна вещь, с которой я столкнулся при решении этой проблемы, заключается в том, что если вы используете комбинацию:

chroot = /path/to/site
chdir = /

В конфигурации пула fpm не указывайте полный путь к ProxyPassдирективе.

ProxyPass fcgi://127.0.0.1:9020/$1

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

тонкий лед
источник
1

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

/programming/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: Ошибка получена:« Основной сценарий неизвестен \ n »».

Надеюсь, этот маленький кусочек поможет кому-то решить свои проблемы.

Biapy
источник
0

у меня ошибка также после перехода на 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

sealionking
источник
[Ср 25 апреля 01: 41: 31.526781 2018] [proxy_fcgi: error] [pid 2012: tid 140181155772160] (70007) Указанный тайм-аут истек: [клиент 127.0.0.1:60308] AH01075: Ошибка отправки запроса к:, рефереру: www / admin / reports
морской котик
0

Я сталкиваюсь с такими же проблемами на моем сервере (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

лимон
источник
0

Это работает с 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 repo, так что вы можете найти его в сети и спросить его, сделает ли он 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 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

On 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 
Галл Аноним
источник