switch apache from prefork to event in Ubuntu 16, get php 7 working
Apache was running slow in production. After searching for answers for some time, I finally went to #apache IRC channel and the pros had me check the apache mode with this command:
sudo apachectl -V
and were alarmed to find that Server MPM is prefork. They emphatically said DO NOT USE PREFORK ON A PRODUCTION SERVER. As it turns out, the Ubuntu packages (presumably inherited from Debian?) insist on running apache in prefork mode despite the fact that the recommended method for running PHP with Apache clearly recommends proxy_fcgi and php-fpm, then fcgid and ultimately says you should not use prefork:
Why you shouldn't use mod_php with the prefork mpm anymore
- mod_php is loaded into every httpd process all the time. Even when httpd is serving static/non php content, that memory is in use.
- mod_php is not thread safe and forces you to stick with the prefork mpm (multi process, no threads), which is the slowest possible configuration
That page also contains some detail on PHP-FPM but this seems a bit elaborate and unclear and seems to involve a lot of manual configuration. I'm disappointed and surprised Ubuntu 16 has no package option for fastCGI mode or something.
I tried switching apache to event mode using a2enmod and when I tried to fire apache back up, I got an error:
Apache is running a threaded MPM, but your PHP Module is not compiled to be threadsafe. You need to recompile PHP
At any rate, I was wondering if anyone had some minimal, step-by-step instructions to get fastCGI mode running on Ubuntu 16 with PHP 7.0 by relying on the package installers as much as possible. I'm currently looking at a lot of poorly explained, vague instructions and I'm concerned about mucking up my production environment with poor decisions.
Also, someone should add mpm-event as a tag option. That's what the #apache IRC guys recommended.
Solution 1:
ezra-s suggests a good approach but it doesn't include some details that might be confusing for folks who rely on package managers. NOTE: I'm not sure if these steps are exact. If anyone encounters trouble or sees issues then let me know and I'll update this post.
Firstly, as of this writing, Ubuntu's apache2 packages insist on prefork if you want to install PHP. Don't despair, however, because you can still use package installers to install and update PHP and apache2 and still get your configuration working with Apache in event mode using PHP-FPM as recommended by the Apache wiki and described in more detail in High-performance PHP on apache httpd 2.4.x using mod_proxy_fcgi and php-fpm. The basic idea is that apache2 and PHP-FPM communicate via socket rather than PHP running as an Apache module.
1) Remove or disable the Apache PHP module
Because the Ubuntu packages insist on prefork Apache when installing PHP, we have to separate them. I did this by using apt to uninstall libapache2-mod-php7.0 because I no longer need the package:
sudo apt-get remove libapache2-mod-php7.0
Alternatively, you might disable the php7.0 Apache module instead, but this will not remove the apt package from your system, which leaves behind annoying system cruft.
sudo a2dismod php7.0
2) Switch Apache to event mode and enable fcgid
I believe these commands should do the trick:
sudo a2dismod mpm_prefork
sudo a2enmod mpm_event
sudo a2enmod proxy_fcgi
3) Install PHP-FPM
I already have PHP 7 installed with its various modules, so I just install PHP-FPM with this command:
sudo apt-get install php7.0-fpm
4) Edit your VirtualHost configuration to handle PHP files with PHP-FPM:
In my case, I edited the default SSL host, /etc/apache2/sites-available/default-ssl.conf, and added this line right near the top:
ProxyPassMatch ^/(.*\.php(/.*)?)$ unix:/run/php/php7.0-fpm.sock|fcgi://localhost/var/www/html/
IMPORTANT This instructs Apache to handle PHP file requests with PHP-FPRM and the the path in this directive (/run/php/php7.0-fpm.sock) must match the path specified by the listen directive in the file /etc/php/7.0/fpm/pool.d/www.conf
5) Restart Apache
sudo service apache2 restart
To check if event mode is enabled, use this command:
sudo apachectl -V
In the output, you should see this:
Server MPM: event
Try creating a phpinfo page and accessing it in your browser. You should see Server API: FPM/FastCGI
in the output.
Solution 2:
Distros offer the "mod_php" method for convenience.
While the most performant way is apache w/event + mod_proxy_fcgi -> php-fpm.
Perhaps they should upgrade with the times but its hard for them when so many frameworks come with .htaccess mod_php configurations in a kind of "plug & play" fashion. At the end, it is the admin the only one responsible to administer and configure their site correctly.
If you are in production I would suggest you use a test server to practice the upgrade and changes.
About the wiki I prefer or would suggest you the "handler" method. https://wiki.apache.org/httpd/PHP-FPM#Proxy_via_handler.
That is, configure php-fpm to have a socket ready and with enough permissions for the Apache user to send requests to it and configure Apache to use it.
A quick example:
# needed modules for reverse proxying to php-fpm
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
<Virtualhost *:443>
ServerName whatever.example.com
#other typical directives here
<Directory /var/www/php-app>
<FilesMatch \.php>
SetHandler "proxy:unix:/path/to/app.sock|fcgi://localhost/"
<FilesMatch>
</Directory>
</VirtualHost>
Edit:
With this way it does not matter which PHP version you use because Apache does not care, it will just reverse proxy the appropriate requests to php-fpm.
Also, don't forget to unload mod_php to be able to use mpm_event.
Edit 2:
As per request, you don't need to uninstall mod_php packages from debian/ubuntu, Apache only cares about its configuration, so unloading the module will do.