001-linkedin-logotype-button 002-twitter-logo 003-social

L'installation "classique" d'un serveur LAMP s'appuie sur Apache associé à son module mod_php. C'est une configuration très répandue car elle est simple. Mais on lui reproche souvent ses mauvaise performances, un manque d'isolation ou sa rigidité. On se tourne alors vers php-fpm. Contrairement aux idées reçues, cet environnement s'installe très facilement et offre de nombreux avantages !

Présentation de php-fpm

Lors de sa conférence au PHP Tour 2016, Rémi Collet nous expliquait pourquoi il fallait absolument proscrire mod_php. On devrait lui préférer php-fpm (FastCGI process manager), un service indépendant qui communique avec Apache à travers le protocole FastCGI. Je conclus de cette présentation que c'est effectivement simple de basculer vers php-fpm et que les avantages présentés semblent incontestables, aussi bien pour de la production que pour du développement ! Deux d'entre eux m'ont particulièrement convaincus.

Les pools

Un pool permet de déclarer une configuration spécifique par application. On va pouvoir y définir des choses très intéressantes comme

  • l'utilisateur qui exécute PHP (fini les problèmes de permissions qu'on doit partager avec l'utilisateur apache)
  • le nombre de processus qu'on veut exécuter (pratique pour gérer la charge)
  • gérer les permissions (en définissant un chroot par exemple)
  • éditer des configurations php spécifiques à notre application (comme on savait le faire dans les vhosts apache)

Un service indépendant

Comme php-fpm est un service indépendant, vous pouvez installer php5 et php7 pour exécuter les deux services en parallèle. Sur une seule machine avec un seul serveur http, on peut donc faire tourner des applications sous php5 et d'autres sous php7. On peut aussi basculer rapidement une application vers php7 pour la tester et la migrer progressivement... Pratique !

Installation

Si mod_php est installé, on commence par le supprimer. Puis on installe php-fpm

apt-get remove libapache2-mod-php5
apt-get install php5-fpm

Sinon, on installe apache, php-fpm

apt-get install apache2 php5-fpm

Bien sûr on peut toujours installer nos autres paquets favoris, comme php5-mysql. La configuration générale de PHP se situe maintenant dans le fichier /etc/php5/fpm/php.ini. Enfin, on active le module proxy_fcgi qui va nous permettre de communiquer avec php-fpm.

a2enmod proxy proxy_fcgi
service apache2 restart

Attention, il existe beaucoup de sources qui s'appuient sur le module mod_fastcgi qui est déprécié et qu'il ne faut donc plus utiliser.

Créer un pool php

Les pools sont configurés dans le dossier /etc/php5/fpm/pool.d, chaque pool est déclaré individuellement dans un fichier *.conf. php-fpm est livré avec un pool par défaut nommé "www", configuré dans le fichier /etc/php5/fpm/pool.d/www.conf. Ce fichier est très bien documenté, je vous conseille donc de le conserver même si vous ne souhaitez pas utiliser ce pool.

Voici par exemple à quoi pourrait ressembler le pool dédié à mon blog.

#/etc/php5/fpm/pool.d/blog.conf

[blog]

user = toto
group = toto
listen = /var/run/php5-fpm-blog.sock
listen.owner = www-data
listen.group = www-data
php_admin_value[open_basedir] = /home/toto/blog:/tpm

; mandatory values
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3

Les processus de ce pool seront lancés par l'utilisateur "toto", c'est beaucoup plus pratique que les processus lancés avec "www-data" en mod_php ! Le pool écoutera un socket unix /var/run/php5-fpm-blog.sock accessible à l'utilisateur "www-data". Notez qu'on peut également écouter un socket TCP, en IPv4 et/ou IPv6. Enfin, on peut aussi ajouter des configurations php (comme open_basedir).

Il faut aussi configurer le process manager afin qu'il sache comment gérer les processus. Il existe 3 modes

  • static : le pool sera toujours lancé avec le même nombre de processus.
  • dynamic : le pool va créer des processus en fonction de la charge (dans les limites qu'on va fixer)
  • ondemand : le pool va créer des processus uniquement lorsqu'on va lui demander (pratique pour du dév).

Pour plus d'informations, se référer au fichier /etc/php5/fpm/pool.d/www.conf. On peut maintenant redémarrer le service php-fpm, et vérifier les processus lancés :

service php5-fpm restart
service php5-fpm status
● php5-fpm.service - The PHP FastCGI Process Manager
   Loaded: loaded (/lib/systemd/system/php5-fpm.service; enabled)
   Active: active (running) since dim. 2017-04-02 00:27:11 CEST; 2s ago
  Process: 3790 ExecStartPre=/usr/lib/php5/php5-fpm-checkconf (code=exited, status=0/SUCCESS)
 Main PID: 3796 (php5-fpm)
   Status: "Ready to handle connections"
   CGroup: /system.slice/php5-fpm.service
           ├─3796 php-fpm: master process (/etc/php5/fpm/php-fpm.conf)
           ├─3799 php-fpm: pool blog
           ├─3800 php-fpm: pool blog

Configuration Apache

Passons maintenant à la configuration d'un VirtualHost Apache. En 3 lignes c'est réglé ! On explique à Apache qu'il doit s'adresser au socket unix qu'on a défini dans notre pool lorsqu'il rencontre un fichier *.php. C'est tout !

# /etc/apache2/sites-availables/blog.conf
<VirtualHost *:80>
    ServerName blog.toto
    DocumentRoot /home/toto/blog

    <Directory /home/user/blog>
        Require all granted
    </Directory>

    <FilesMatch \.php$>
        SetHandler "proxy:unix:/var/run/php5-fpm-blog.sock|fcgi://localhost/"
    </FilesMatch>
</VirtualHost>

On n'a plus qu'à ajouter notre site et recharger la configuration Apache !

a2ensite blog.conf
service apache reload

Problèmes rencontrés

Je vous ai parlé de la possibilité de chrooter un pool. En effet, c'est rassurant de pouvoir enfermer PHP dans son répertoire de travail, surtout lorsqu'on héberge plusieurs applications ! J'ai donc expérimenté et j'ai rencontré un petit problème dont la solution, peu élégante à mon gout, est évoquée dans ce trhead.