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 з body 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/ назад" до прямої.


Будь-які ідеї?

Відповіді:


34

Після годин пошуку та читання документації Apache я придумав рішення, яке дозволяє використовувати пул, а також дозволить директиві Переписати в .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.

Я сподіваюся, що це рішення допоможе і вам.


2
Це, безумовно, відповідь на 2015 рік, все інше тут лайно для сучасного налаштування (Скажімо, debian stable)
Дмитрій БД

1
Я б'є головою об стіну по цій самій проблемі вже досить давно, і у мене надзвичайно схожа установка, як і ваша. Чи можете ви розмістити свої .htaccess Переписати директиви? Як я розумію, у цій відповіді все є лише тим, що є у вашому файлі httpd.d / site.conf.
David W

1
На даний момент використання цього RewriteRule видається досить небезпечним, оскільки воно може викрити config.php файли в простому форматі, якщо вони знаходяться у довідниках Aliased і тому не існують у% {DOCUMENT_ROOT} /% {REQUEST_URI}.
Зулакіс

1
Дивовижні 9 рядків коду. Це святий грааль і єдине, що для мене працює на 100%. Просто сторонне позначення: Якщо ви переходите з рішення за допомогою LocationMatch, вам не потрібно додавати абсолютний шлях до файлу до URL-адреси fcgi. Увімкніть проксі і перепишіть вхід у систему apache, щоб стежити за цим.
Філ

1
+1, оскільки ця публікація, на відміну від будь-якого іншого ресурсу, який я бачив, допомогла мені зрозуміти, що "унікальний домен-рядок-ім'я" повинен являти собою.
тридцять

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 у вашій системі, поза тим, як вони хочуть використовувати ті самі порти.)


Це хороше рішення, але, на жаль, такий підхід не працює, коли 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

Я намагався зробити щось подібне без переписувань ("Якщо" і таке), але мені нічого не вдалося.

EDIT: Зауважте, що якщо ви реалізовували це як спільний провайдер хостингу, це може бути проблемою безпеки. Це дозволить користувачам передавати скрипти PHP до будь-якого проксі-сервера fcgi. Якщо у вас був окремий пул для кожного користувача, це дозволило б збільшити привілейовані атаки.


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.

BTW: Для тих, хто мав би ідею встановити ProxyErrorOverride на On , пам’ятайте, що це дійсно погана ідея. Використання цієї директиви не викликає жодних проблем. Наприклад, будь-яка програма PHP, що надсилає HTTP-код, наприклад 503, призведе до несподіваного результату. Обробник помилок за замовчуванням буде задіяний у будь-яких випадках і для PHP-програм, які надають API, це справді погана поведінка.


На жаль, все ще була помилка "AH01071: Отримана помилка" Невідома основна скрипт \ n "" за допомогою цього рішення.
klor

1

Найкращий спосіб вирішити це - увімкнути журнали налагодження для mod_proxy та mod_rewrite та php-fpm. Тепер у апачі 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>

1

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

chroot = /path/to/site
chdir = /

У конфігурації пулу fpm не переходьте повний шлях до ProxyPassдирективи.

ProxyPass fcgi://127.0.0.1:9020/$1

Але -ЛІНО- якщо басейн на цьому порту закріплений.


1

Я не впевнений, що проблема пов’язана, але я знайшов тут частково працююче рішення:

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: Отримана помилка" Невідомий первинний сценарій \ n "".

Сподіваюсь, цей маленький ласощі допоможе комусь вирішити свої проблеми.



0

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


[Ср. 25 квітня 01: 41: 31.526781 2018] [proxy_fcgi: помилка] [pid 2012: tid 140181155772160] (70007) Зазначений час очікування закінчився: [клієнт 127.0.0.1:60308] AH01075: Помилка надсилання запиту на адресу:, референт: www / admin /
messages

0

Я зіткнувся з тими ж проблемами на своєму сервері (докер centos 7.3.16). Після відстеження журналу php-fpm я виявив, що пропускаю sys lib. 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 repo працює лише в режимі 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

скопіюйте це у файл 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 був встановлений і налаштований раніше на початку конфігурації cert 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 
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.