How to Install PHP-FPM with Apache on Ubuntu 18.04 – Google Cloud

How to install PHP 7.4-FPM with Apache on Ubuntu 18.04 in Google Cloud Platform. There are two distinct options to run PHP using the web server. One is using the PHP’s CGI and the other one is FPM.

FPM is a process manager to manage the FastCGI in PHP. Apache ships with mod_php by default and works with all major web servers. With mod_php there is a little performance issue because it locks out the process.

You can also configure PHP-FPM pools to run as the different user that owns the website if you are hosting multiple websites on your server in a chroot environment setup.

Getting Started

Make sure your Ubuntu server is having the latest packages by running the following command.

sudo apt update
sudo apt upgrade

This will update the package index and update the installed packages to the latest version.

Add PPA for PHP 7.4

Add the ondrej/php which has PHP 7.4 package and other required PHP extensions.

sudo apt install software-properties-common
sudo add-apt-repository ppa:ondrej/php
sudo apt update

Once you have added the PPA you can install PHP 7.4.

Install PHP 7.4 FPM

Now we shall install PHP 7.4-FPM and some common modules to run a PHP application like WordPress.

sudo apt install php7.4-fpm php7.4-common php7.4-mysql php7.4-xml php7.4-xmlrpc php7.4-curl php7.4-gd php7.4-imagick php7.4-cli php7.4-dev php7.4-imap php7.4-mbstring php7.4-soap php7.4-zip php7.4-bcmath -y

Wait for the installation to complete.

Once the installation is complete verify the installation using the following command.

sudo service php7.4-fpm status

You will receive an output similar to the one below.

Output
● php7.4-fpm.service - The PHP 7.4 FastCGI Process Manager
    Loaded: loaded (/lib/systemd/system/php7.4-fpm.service; enabled; vendor preset: enabled)
    Active: active (running) since Thu 2020-01-09 08:36:51 UTC; 1min 48s ago
      Docs: man:php-fpm7.4(8)
  Main PID: 15920 (php-fpm7.4)
    Status: "Processes active: 0, idle: 2, Requests: 0, slow: 0, Traffic: 0req/sec"
     Tasks: 3 (limit: 669)
    CGroup: /system.slice/php7.4-fpm.service
            ├─15920 php-fpm: master process (/etc/php/7.4/fpm/php-fpm.conf)
            ├─15938 php-fpm: pool www
            └─15939 php-fpm: pool www

Install Apache

Once you have your PHP-FPM up and running you can install Apache web server.

sudo apt install apache2

Configure Apache with PHP-FPM

By default Apache will use mod_php so now you can configure Apache to use PHP-FPM.

Disable the default Apache vhost configuration.

sudo a2dissite 000-default

Enable proxy_fcgi module.

sudo a2enmod proxy_fcgi

Create a new Apache vhost configuration.

sudo nano /etc/apache2/sites-available/cloudbooklet.conf

Paste the below configuration in the file.

<VirtualHost *:80>
     ServerName External_IP_Address
     DocumentRoot /var/www/html

     <Directory /var/www/html>
          Options Indexes FollowSymLinks
         AllowOverride All
         Require all granted
     </Directory>

     <FilesMatch ".php$"> 
         SetHandler "proxy:unix:/var/run/php/php7.4-fpm.sock|fcgi://localhost/"          
      </FilesMatch>
 
      ErrorLog ${APACHE_LOG_DIR}/error.log
      CustomLog ${APACHE_LOG_DIR}/access.log combined  
</VirtualHost>

Hit CTRL + X followed by Y and Enter to save and exit the file.

Now you can enable the new Apache configuration.

sudo a2ensite cloudbooklet.conf

Restart Apache.

sudo service apache2 restart

Test PHP-FPM with Apache

Here we have configured /var/www/html as the webroot in the Apache configuration. So now you can navigate into that directory and create a phpinfo file to check the setup.

cd /var/www/html
sudo nano info.php

Paste the following.

<?php phpinfo;

Hit CTRL + X followed by Y and Enter to save and exit the file.

Now go your browser and point it to your server IP address or domain name followed by the info.php. So your address will look like this http://IP_Address/info.php

You will see the PHP info page and confirm PHP-FPM is used with Apache.

PHP-FPM Configuration

PHP INI: /etc/php/7.4/fpm/php.ini

Pool config: /etc/php/7.4/fpm/pool.d/www.conf

Create New PHP-FPM Pool with different user

By default Nginx and Apache runs as www-data user. PHP-FPM www.conf is also configured to run as www-data user. If you have multiple websites and wish to keep them isolated with chrooted setup and run them with their own user. You can create multiple PHP-FPM pools with different users.

Create a new PHP-FPM pool configuration.

sudo nano /etc/php/7.4/fpm/pool.d/user1.conf

Paste the following.

[user1]
user = user1
group = group1

listen = /run/php/php7.4-fpm-user1.sock

listen.owner = www-data
listen.group = www-data

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

Now create a new Apache vhost configuration file and set the handler to the new pool you have created.

sudo nano /etc/apache2/sites-available/site1.conf
<VirtualHost *:80>
     ServerName domain.com
     DocumentRoot /var/www/html/site1

     <Directory /var/www/html/site1>
          Options Indexes FollowSymLinks
         AllowOverride All
         Require all granted
     </Directory>

     <FilesMatch ".php$"> 
         SetHandler "proxy:unix:/var/run/php/php7.4-fpm-user1.sock|fcgi://localhost/"          
      </FilesMatch>
 
      ErrorLog ${APACHE_LOG_DIR}/error.log
      CustomLog ${APACHE_LOG_DIR}/access.log combined  
</VirtualHost>

Enable new site.

sudo a2ensite site1.conf

Make sure the new site webroot is owned by the user specified in the pool configuration and inside the specified group.

Restart Services

Once the configuration is completed you need to restart PHP-FPM and Apache for the changes to take effect.

sudo php-fpm7.4 -t
sudo service php7.4-fpm restart
sudo service apache2 restart

You can create as many pools you like using the above mentioned setup with PHP-FPM. These are the flexibility available with PHP-FPM.

Conclusion

Now you have learned how to install PHP 7.4-FPM with Apache and configure Apache. You have also learned to setup PHP-FPM pools for multiple users.

PHP-FPM settings tutorial. max_servers, min_servers, etc.

You need to know three things about your server before you change PHP FPM’s settings:

  1. How many cores does your server have?
  2. The amount of memory (RAM) on your server.
  3. How much memory does the average PHP process consume on your server?

How many cores does your server have?

To find out how many cores your server has, run the following command:

When you run the Linux command above, you will get something like “Cores = 4”.

Jot that figure down because it’s important.

How much memory does your server have?

You should already know how much memory your server has. The real question here is: “How much memory do you want to give PHP?”

You have to take into account the fact that your server might be also running NGINX, Apache or MySQL. How much memory are these other processes consuming? If you have 8GB of RAM and the other processes on your machine are consuming 2GB, that leaves you with 6GB – or 5GB if you want to play it safe and leave some free.

Figure out how much memory you want to give PHP and jot that down. In my case, I had 4GB that I could allocate to PHP.

On average, how much memory does each PHP process consume?

This will depend on your application and your version of PHP. Older versions of PHP tend to consume more memory than PHP 7.

Run the command below to get a general idea of how much memory each PHP FPM process is consuming.

Note that the command above above is looking for a process called php-fpm7.2. The PHP process on your server might be called something different. To find out the name of your PHP process, use the top command. When you run the top command, you will probably see one of the following processes:

  • php-fpm
  • php5-fpm
  • php7.0-fpm
  • php7.1-fpm
  • php7.2-fpm

When I ran the command above, I got 29M. i.e. Each php-fpm7.2 process on my server consumes about 29MB in RAM.

The configuration settings.

I now have three important pieces of information:

  • My server has 4 cores.
  • I can allocate about 4GB of RAM to PHP.
  • Each PHP FPM process on my server consumes about 29MB of memory. On older versions of PHP, you will probably see that each process consumes a lot more than that. I was reaching about 90MB per process when I was running the exact same application on PHP 5.5.

Now it is time to edit the www.conf file, which is situated in the pool.d directory. On my server, it was located at:

/etc/php/7.2/fpm/pool.d/www.conf

On your machine, the location might be slightly different.

There are 4 configuration values that we are going to change in the www.conf file:

  • pm.max_children
  • pm.start_servers
  • pm.min_spare_servers
  • pm.max_spare_servers

pm.max_children

To get a good value for this, you should take the memory that you want to allocate to PHP FPM and divide it by the average memory that is consumed by each PHP FPM process.

In my case, I want to allocate 4GB (4000MB) and each process consumes about 29MB.

Divide 4000 by 29 and you get around 138.

So I set pm.max_children to 138.

If you have 8000MB to spare and your PHP consumes about 80MB per process, then that will be: 8000 / 80 = 100.

pm.start_servers

For pm.start_servers, I multiply the number of cores that I have by 4.

4 x 4 = 16

So I set pm.start_servers to 16.

If you have 8 cores, then it will be: 4 x 8 = 32.

pm.min_spare_servers

For pm.min_spare_servers, multiply the number of cores that you have by 2.

In my case, that is 2 x 4 = 8.

So I set pm.min_spare_servers to 8.

pm.max_spare_servers

For pm.max_spare_servers, multiply the number of cores on your server by 4.

On my machine, that is 4 x 4 = 16.

So I set pm.max_spare_servers to 16, the same value that I used for pm.start_servers.

Restart PHP FPM.

For these changes to take affect, you will need to restart PHP FPM. Below, I have included a number of service restart commands that might apply to your setup. Select the correct one and run it.

Anyway, hopefully you found this guide useful!

A better way to run PHP-FPM

If you search the web for PHP-FPM configurations, you’ll find many of the same configurations popping up. They nearly all use the ‘dynamic’ process manager and all assume you will have one master process for running PHP-FPM configurations. While there’s nothing technically wrong with that, there is a better way to run PHP-FPM.

In this blogpost I’ll detail;

  1. Why ‘dynamic’ should not be your default process manager
  2. Why it’s better to have multiple PHP-FPM masters

.. If you’re working on a high performance PHP setup, the ‘ondemand’ PM may not be for you. In that case, it’s wise to pre-fork your PHP-FPM processes up to the maximum your server can handle. That way, all your processes are ready to serve your requests without needing to be spawned first. However, for 90% of the sites out there, the ondemand PHP-FPM configuration is better than either static or dynamic.

How to reduce PHP-FPM (php5-fpm) RAM usage by about 50%

I became aware of what an alternative configuration would do after reading an article titled A better way to run PHP-FPM. It was written about a year ago, so it’s kinda disappointing that I came across it while searching for a related topic just last night. If you run your own server and use PHP with PHP-FPM, you need to read that article.

After I read it, I changed the pm options in the pool configuration file to these:

The major change was setting pm = ondemand instead of pm = dynamic. And the impact on resource usage was drastic. Here, for example, is the output of

Related Post:  Eyes in the Sky: The Rise of Gorgon Stare and How It Will Watch Us All

free mt after reloading php5-fpm:

Compared to the output before, that’s more than a 50% drop in RAM usage. And the reason became obvious when I viewed top again:

Did you notice that there are no child processes? What happened to them? That’s what setting pm = ondemand does. A child process is spawned only when needed. After it’s done its job, it remains idle for 10 seconds (pm.process_idle_timeout = 10s) and then dies.

So what I have is a simple modification to the default PHP-FPM settings that saved me more than 50% of RAM. Sure, the server hasn’t come under heavy traffic, but I think it can withstand a reasonably heavy traffic, considering that it only has 512 MB of RAM. And with Nginx microcaching configured, I think it will do very well. There are other aspects of PHP-FPM and Percona MySQL that I’ve not optimized yet, so stay tuned. This was just to pass on a little tip that I found useful.