Apache 2.4 + PHP-FPM + ProxyPassMatch


31

J'ai récemment installé Apache 2.4 sur ma machine locale, ainsi que PHP 5.4.8 en utilisant PHP-FPM.

Tout s'est bien passé (après un certain temps ...) mais il y a quand même une étrange erreur:

J'ai configuré Apache pour PHP-FPM comme ceci:

<VirtualHost *:80>
    ServerName localhost
    DocumentRoot "/Users/apfelbox/WebServer"
    ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/Users/apfelbox/WebServer/$1
</VirtualHost>

Cela fonctionne, par exemple si j'appelle, http://localhost/info.phpj'obtiens le bon phpinfo()(c'est juste un fichier de test).

Si j'appelle un répertoire cependant, j'obtiens un 404 avec le corps File not found.et dans le journal des erreurs:

[Tue Nov 20 21:27:25.191625 2012] [proxy_fcgi:error] [pid 28997] [client ::1:57204] AH01071: Got error 'Primary script unknown\n'

Mise à jour

J'ai maintenant essayé de faire le proxy avec 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>

Mais le problème est: il est toujours en train de rediriger, car on http://localhost/le http://localhost/index.phpdemande automatiquement , à cause de

DirectoryIndex index.php index.html

Mise à jour 2

Ok, donc je pense "peut-être vérifier s'il y a un fichier à donner au proxy en premier:

<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>

Maintenant, la réécriture complète ne fonctionne plus ...

Mise à jour 3

Maintenant, j'ai cette solution:

<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>

Vérifiez d'abord qu'il y a un fichier à passer à PHP-FPM (avec le chemin complet et absolu ) puis faites la réécriture.

Cela ne fonctionne pas lorsque vous utilisez la réécriture d' URL dans un sous - répertoire, aussi échoue pour les URL comme http://localhost/index.php/test/ donc retour à la case départ .


Des idées?

Réponses:


34

Après des heures de recherche et de lecture de la documentation Apache, j'ai trouvé une solution qui permet d'utiliser le pool, et aussi de permettre à la directive Rewrite dans .htaccess de fonctionner même lorsque l'url contient des fichiers .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>

Selon la documentation Apache, le paramètre proxy SetHandler nécessite Apache HTTP Server 2.4.10.

J'espère que cette solution vous aidera aussi.


2
C'est définitivement la réponse pour 2015, tout le reste ici est de la merde pour une configuration moderne (disons stable Debian)
Dmitri DB

1
Je me tape la tête contre le mur sur ce même problème depuis un certain temps, et j'ai une configuration extrêmement similaire à la vôtre. Souhaitez-vous publier vos directives de réécriture .htaccess? D'après ce que je comprends, tout dans cette réponse n'est que ce que vous avez dans votre fichier httpd.d / site.conf.
David W

1
À l'heure actuelle, l'utilisation de cette RewriteRule semble assez dangereuse car elle pourrait exposer des config.php fichiers en clair s'ils se trouvaient dans des répertoires aliasés et donc n'existant pas dans% {DOCUMENT_ROOT} /% {REQUEST_URI}.
Zulakis

1
Incroyable 9 lignes de code. C'est le Saint Graal et la seule chose qui fonctionne à 100% pour moi. Juste une note: si vous passez d'une solution à l'aide de LocationMatch, vous n'avez pas besoin d'ajouter le chemin de fichier absolu à l'URL fcgi. Activez le proxy et réécrivez la connexion dans apache pour faire attention à cela.
Phil

1
+1, car ce message, contrairement à toutes les autres ressources que j'ai vues, m'a aidé à comprendre ce que "chaîne de nom de domaine unique" est censé représenter.
threeve

10

J'ai également rencontré ce problème hier - Apache 2.4 est passé de Debian / experimental à Debian / unstable, me forçant à gérer ce nouveau truc; pas sur nos serveurs de production bien sûr;).

Après avoir lu ce qui ressemble à des millions de sites, des documents Apache, des rapports de bogues et une sortie de débogage dans le journal des erreurs, j'ai finalement réussi à le faire fonctionner. Non, il n'y a pas encore de support pour FPM avec des sockets . La configuration par défaut de Debian utilise des sockets depuis un certain temps maintenant, donc les utilisateurs de Debian devront également changer cela.

Voici ce qui fonctionne pour un site CakePHP et PHPMyAdmin (ce dernier a besoin d'une configuration si vous utilisez les paquets Debian), donc je peux confirmer que cela mod_rewritefonctionne toujours comme prévu pour faire une réécriture d'URL de fantaisie.

Remarquez DirectoryIndex index.php, ce qui pourrait être la raison pour laquelle aucune de vos configurations n'a fonctionné pour les "dossiers" (du moins c'est ce qui n'a pas fonctionné ici).

J'obtiens toujours File not found.des répertoires, mais seulement s'il n'y a pas de fichier d'index, il peut analyser. J'adorerais me débarrasser de cela aussi, mais ce n'est pas aussi critique que pour le moment.


<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>

Le vhost ci-dessus fonctionne parfaitement bien avec un .htaccess à la racine comme ceci:

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

Je ne comprends pas vraiment ce que vous voulez dire par contre URL rewriting inside a subdirectory(je ne fais que réécrire dans le fichier index.php de la racine).


(Oh, et vous devrez vous assurer que Xdebug n'entre pas en conflit avec FPM sur votre système, dès le départ, ils veulent utiliser les mêmes ports.)


C'est une bonne solution mais malheureusement cette approche ne fonctionne pas lorsque les URL contenant .php doivent être réécrites, par exemple pour WordPress multisite. /ms_blog_1/wp-admin/load-scripts.php?blah=blah
Phil

Pour moi, l'ajout d'un remplacement DirectoryIndex index.htmldans le vhost en question l'a corrigé. Si c'est le cas DirectoryIndex index.php, il semble que d'autres fichiers PHP finissent par donner l'erreur «Fichier introuvable» et «Script principal inconnu». Dans mon cas, j'ai index.htmlun fichier php test.php.
geerlingguy

4

Il vous suffit de définir:

 ProxyErrorOverride on

Et n'oubliez pas de paramétrer la page client en:

ErrorDocument 404 /path/to/error_page_file    

2

Voilà ce que j'ai. Il semble fonctionner correctement. J'ai mis Drupal dans un sous-répertoire et son travail de réécriture, les index de répertoire fonctionnent et PATH_INFO fonctionne.

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

J'ai essayé de faire quelque chose comme ça sans réécriture ("Si" et autres), mais je n'ai rien pu faire fonctionner.

EDIT: Notez que si vous l'implémentiez en tant que fournisseur d'hébergement partagé, cela pourrait être un problème de sécurité. Cela permettrait aux utilisateurs de passer des scripts PHP à un proxy fcgi arbitraire. Si vous aviez un pool séparé pour chaque utilisateur, cela permettrait une élévation des attaques de privilèges.


2

Encore une autre solution (nécessite Apache> = 2.4.10) - À l'intérieur du 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>

Donc, ici, le gestionnaire fcgi pour PHP ne sera défini que si le fichier existe et si son nom correspond à l'extension de fichier PHP.

BTW: Pour ceux qui auraient l'idée de régler ProxyErrorOverride sur On , sachez que c'est vraiment une mauvaise idée. L'utilisation de cette directive n'est pas sans poser de problème. Par exemple, toute application PHP envoyant du code HTTP tel que 503 entraînerait un résultat inattendu. Le gestionnaire d'erreurs par défaut serait impliqué dans tous les cas et pour les applications PHP qui fournissent une API, c'est vraiment un mauvais comportement.


Malheureusement, il y avait toujours une erreur "AH01071: Got error 'Primary script unknown \ n'" lors de l'utilisation de cette solution.
klor

1

La meilleure façon de résoudre ce problème est d'activer les journaux de débogage pour mod_proxy et mod_rewrite et php-fpm. Dans apache 2.4, vous pouvez désormais activer les journaux de débogage pour des modules spécifiques uniquement. http://httpd.apache.org/docs/current/mod/core.html#loglevel La configuration par module et par répertoire est disponible dans Apache HTTP Server 2.3.6 et versions ultérieures

Peut-être que vous obtenez une double barre oblique sur les répertoires?

Voici ce que j'utilise et cela fonctionne bien:

<LocationMatch ^(.*\.php)$>
  ProxyPass fcgi://127.0.0.1:9000/home/DOMAINUSER/public_html$1
</LocationMatch>

1

Une chose que j'ai rencontrée dans mon traitement de ce problème est que si vous utilisez la combinaison de:

chroot = /path/to/site
chdir = /

Dans votre configuration de pool fpm, ne passez pas le chemin d'accès complet à la ProxyPassdirective.

ProxyPass fcgi://127.0.0.1:9020/$1

Mais -Seulement- si le pool sur ce port est chrooté.


1

Je ne sais pas si le problème est lié, mais j'ai trouvé une solution de travail partielle ici:

/programming/44054617/mod-rewrite-in-2-4-25-triggering-fcgi-primary-script-unknown-error-in-php-fpm

L'astuce semble être d'ajouter un? char dans le .htaccess RewriteRule, par exemple en utilisant:

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

au lieu de:

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

La source du problème semble être un changement dans mod_rewrite d'Apache 2.4.25. J'ai utilisé le niveau de log d'Apache trace1 pour observer une "boucle" qui passe $ 1 à php-fpm après que index.php / $ 1 a été passé. Le $ 1 génère l'erreur "AH01071: Got error 'Primary script unknown \ n'".

J'espère que cette petite friandise aidera quelqu'un à résoudre ses problèmes.



0

j'ai l'erreur également après le passage à php-fpm + apache 2.4.6 pour les instances drupal

mais j'utilise le mod d'événement mpm

il suffit d'insérer

DirectoryIndex index.php travaille pour moi

alors mes paramètres Vhost ressemblent à ci-dessous

<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>

Merci

pas besoin de réviser le fichier .htaccess par défaut de drupal


[Mer 25 avr 01: 41: 31.526781 2018] [proxy_fcgi: erreur] [pid 2012: tid 140181155772160] (70007) Le délai spécifié a expiré: [client 127.0.0.1.160608] AH01075: Erreur lors de l'envoi de la demande à:, référent: www / admin / reports
sealionking

0

Je fais face aux mêmes problèmes sur mon serveur (docker centos 7.3.16). Après avoir suivi le journal de php-fpm, j'ai trouvé miss a sys lib. WARNING: [pool www] child 15081 said into stderr: "php-fpm: pool www: symbol lookup error: /lib64/libnsssysinit.so: undefined symbol: PR_GetEnvSecure" puis, je rappelle le nspr, cela fonctionne. Si vous ne trouvez pas les solutions après avoir essayé des méthodes, vous pouvez essayer ceci. yum -y install/reinstall nspr


0

Cela fonctionne avec Wordpress 5.1.1 et plus récent avec PHP 7.3, FastCGI, proxy, également MariaDB / MySQL. Vérifié deux fois sur mes serveurs. Fonctionne comme un charme.

Premier sur 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

Modifiez ce fichier:

sudo nano /etc/php-fpm.d/www.conf

Collez ceci:

[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

Devrait donner srw-rw-rw-.

Ou comment installer sur Debian / Ubuntu

Didacticiel:

source: 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)

Le problème est que php 7.3 du repo Ondrej ne fonctionne qu'avec le mode mpm_prefork. Il a git repo, vous pouvez donc le trouver dans le net et lui demander s'il fera php 7.3 pour mpm_worker et mpm_event. Le reste de la configuration des distributions de la famille Debian est ci-dessous:


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

coller


[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

coller


[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

coller


[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

copiez ceci dans un fichier txt:

/var/log/php7.3-fpm.log {
    rotate 12
    weekly
    missingok
    notifempty
    compress
    delaycompress
    postrotate
            /usr/lib/php/php7.3-fpm-reopenlogs
    endscript
}

supprimez-le puis collez-le au lieu de ci-dessus:

/var/log/php7.3/*.log /var/log/php7.3-fpm/*.log
{
copytruncate
maxage 365
missingok
monthly
notifempty
rotate 12
}

Ajouter une directive

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>

Activez ensuite le site:

sudo a2ensite /etc/apache2/sites-available/example.com.conf

Modifiez ensuite le site SSL (dans ce cas, le certbot de Let's Encrypt a été installé et configuré précédemment au début de la configuration du certificat 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

N'oubliez pas d'ajouter un port 9000 à un pare-feu sur Debian / Ubuntu

sudo ufw allow 9000/tcp
sudo ufw status

Sur 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 
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.