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

The other day, I was looking around for articles and tips on how to fine tune PHP FPM’s www.conf settings. To my frustration, the official documentation didn’t give any recommendations and there weren’t a whole lot of tutorials on the subject.

After wading through various discussions and blog posts, I managed to piece together the following information.

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: echo Cores = $(( $(lscpu | awk ‘/^Socket/{ print $2 }’) * $(lscpu | awk ‘/^Core/{ print $4 }’) ))

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. ps –no-headers -o “rss,cmd” -C php-fpm7.2 | awk ‘{ sum+=$1 } END { printf (“%d%s\n”, sum/NR/1024,”M”) }’

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:


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


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.


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.


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.


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. sudo service php-fpm restart sudo service php5-fpm restart sudo service php7.0-fpm restart sudo service php7.1-fpm restart sudo service php7.2-fpm restart

Anyway, hopefully you found this guide useful!


How to Change the WordPress Database Prefix to Improve Security

WordPress Database is like a brain for your entire WordPress site because every single information is stored in there thus making it hacker’s favorite target. Spammers and hackers run automated codes for SQL injections. Well, unfortunately many people forget to change the database prefix while they install WordPress. This makes it easier for hackers to plan a mass attack by targeting the default prefix wp_. The smartest way you can protect your database is by changing the database prefix which is really easy to do on a site that you are setting up. But it takes a few steps to change the WordPress database prefix properly for your established site without completely messing it up.

We recommend that you backup your WordPress Database before you perform anything suggested in this tutorial. It is important to keep daily backups of your site, we recommend BackupBuddy plugin for doing that. Next thing we recommend is that you redirect your visitors to a temporary maintenance page.
Change Table Prefix in wp-config.php

Open your wp-config.php file which is located in your WordPress root directory. Change the table prefix line from wp_ to something else like this wp_a123456_

So the line would look like this:

$table_prefix = ‘wp_a123456_’;

Note: You can only change it to numbers, letters, and underscores.
Change all Database Tables Name

Continue reading

Network Booting Raspbian Lite to a Raspberry Pi 4 from a Synology NAS

Work Environment

NAS: Synology DS216+II with DSM 6.1.7-15284

Netgear WNDR3700v2 Router Running Gargoyle Firmware version 1.10.0 or DD-WRT v3.0-r40559 std (08/06/19)

Raspberry Pi

Before you begin

If you have a battery backup unit then enable UPS.

To boot a Raspberry Pi 4 using PXE, there are a few steps required, starting with updating that bootloader firmware. This means installing Raspbian to an SD card and booting the Pi off of it at least once. From there, we turn to the PXE server to build the remote filesystem and set up the NFS and dnsmasq services. This article draws from a pair of official Pi network boot guides.

Bootloader Update

At the time of writing, the eeprom firmware that supports PXE boot is still in beta. We have to grab that firmware, change the boot order configuration, and then flash it to the onboard chip. Once the Pi 4 is booted off your Raspbian SD card, we can do the following to get the firmware updated:

$ sudo apt-get update
$ sudo apt-get upgrade
$ wget
$ rpi-eeprom-config pieeprom-2019-10-16.bin > bootconf.txt
$ sed -i s/0x1/0x21/g bootconf.txt
$ rpi-eeprom-config --out pieeprom-2019-10-16-netboot.bin --config bootconf.txt pieeprom-2019-10-16.bin
$ sudo rpi-eeprom-update -d -f ./pieeprom-2019-10-16-netboot.bin
$ cat /proc/cpuinfo

That last command should output some information on the Pi itself. We’re interested in the entry for the Pi’s serial number. Write down the last 8 characters of that code, as we’ll use it later. That’s all the setup needed for the Pi itself.

Download Raspbian Lite ZIP file and extract the image.

If your router acts as the DHCP server in your network then it will need to support network booting (most do not) if you want to continue to use it as the DHCP server, otherwise you will need to disable DHCP on your router and setup a DHCP server on your NAS. An alternative is to install a Linux firmware to your router if it’s possible (i.e. OpenWRT, DD-WRT, etc.) which is the scenario used for this guide.

Continue reading

Building a TV Server on a Raspberry Pi

Before you begin:

You will need to donate $20 to to get a version of the software that will run on your Synology if it uses an ARM processor and won’t run the standard x86 version that you can download from the site. The DS216+II in this tutorial has an Intel x86 / x64 processor so the standard x86 version will work just fine.

You will also need a subscription to Schedules Direct.

Download Rasbian Lite from the Rasbian website. The iscsi initiator service is missing from this image so you will need to recompile the kernel in order to add it. Once installed, you will need to do the following:

sudo raspi-config #Expand File system and enable SSH
sudo apt-get update
sudo apt-get upgrade

Next, we will need to install some packages for an on-device kernel recompile: Continue reading

How to Build a Custom Desktop with Ubuntu Server

Download Ubuntu Server and install it.

If you have a proprietary graphics card, then add the following PPA:

$ sudo add-apt-repository ppa:oibaf/graphics-drivers

If you want to install the latest version of the Cinnamon Desktop Environment, then add the following PPA:

$ sudo add-apt-repository ppa:embrosyn/cinnamon

If you want to install the latest version of Kodi Media Center, then add the following PPA:

$ sudo add-apt-repository ppa:team-xbmc/ppa

If you want to install Syncthing, then enter the following commands: Continue reading


What is NAT?

NAT (Network Address Translation) is a technology most commonly used by firewalls and routers to allow multiple devices on a LAN with ‘private’ IP addresses to share a single public IP address. A private IP address is an address, which can only be addressed from within the LAN, but not from the Internet outside the LAN. In order to let a device with a private IP address communicate with other devices on the Internet, there needs to be a translation between private and public IP addresses at the point where the LAN connects to the Internet, that is within the firewall/router connecting the LAN to the Internet. Such a translation is commonly referred to as NAT (for Network Address Translation) and a router doing such translation is often called a NAT router or NAT firewall/router. Sometimes NAT is also called IP Masquerading. The passing of traffic through NAT is called NAT Traversal. Continue reading

Spreading a Data Project over Multiple Discs in Linux

After spending hours trying to find software in Linux that can span a large directory over multiple discs without having to create an archive set, I finally came across this small Python script that will do the job.

How to Use

Put the script(s) in your “~/bin/”.

mkdir work/
cd work
mkdir in/
mkdir out/

Make a link copy of your data in the “in” dir:
cp -vrl originals/* in/

The dir work/out/ should contain the output dirs dvd_001, dvd_002, etc… Continue reading

Help, I’ve been blocked from my PBX!

[HOW TO] Help, I’ve been blocked from my PBX!

Note: This post assumes you’re running FreePBX Distro 13 or higher

If your FreePBX instance has suddenly become unreachable, chances are you’ve been blocked by one of the included network security mechanisms in FreePBX. The good news is that it’s working! The bad news is now you have to somehow work out a way to get yourself unblocked, figure out how you got blocked, and stop it from happening again.

What Blocked Me?

Intrusion Detection (fail2ban)

If you’ve suddenly lost access to the server, this is the most likely culprit. Intrusion Detection scans log files and looks for failed login attempts and other types of unauthorized access, and then temporarily bans the IP of the “attacker”. Continue reading

Virtualmin Server Configuration on Vultr VS

Initial Configuration

In your Vultr Control Panel, set up a Ubuntu or Debian Server instance and SSH into it. Then add a repository that will provide your server with multiple PHP versions and update. If you need to you can change the hostname in /etc/hostname and FQDN in /etc/hosts.

For CentOS Install
Change selinux to disabled in /etc/selinux/config and save and reboot.
# yum install centos-release-scl setroubleshoot-server bzip2 -y
# yum update -y
# yum install rh-php71 rh-php71-php-fpm rh-php71-php-cgi rh-php71-php-mysqlnd rh-php71-php-imap rh-php71-php-curl rh-php71-php-gd rh-php71-php-xmlrpc rh-php71-php-xsl rh-php71-php-mbstring rh-php71-php-zip rh-php71-php-cli rh-php71-php-dom rh-php71-php-pdo rh-php71-php-soap rh-php71-php-json rh-php71-php-xml rh-php71-php-pear rh-php71-php-bcmath rh-php71-php-pecl-apcu rh-php71-php-pecl-apcu-devel rh-php71-php-intl -y
# yum install rh-php72 rh-php72-php-fpm rh-php72-php-cgi rh-php72-php-mysqlnd rh-php72-php-imap rh-php72-php-curl rh-php72-php-gd rh-php72-php-xmlrpc rh-php72-php-xsl rh-php72-php-mbstring rh-php72-php-zip rh-php72-php-cli rh-php72-php-dom rh-php72-php-pdo rh-php72-php-soap rh-php72-php-json rh-php72-php-xml rh-php72-php-pear rh-php72-php-bcmath rh-php72-php-pecl-apcu rh-php72-php-pecl-apcu-devel rh-php72-php-intl -y
# yum install rh-php73 rh-php73-php-fpm rh-php73-php-cgi rh-php73-php-mysqlnd rh-php73-php-imap rh-php73-php-curl rh-php73-php-gd rh-php73-php-xmlrpc rh-php73-php-xsl rh-php73-php-mbstring rh-php73-php-zip rh-php73-php-cli rh-php73-php-dom rh-php73-php-pdo rh-php73-php-soap rh-php73-php-json rh-php73-php-xml rh-php73-php-pear rh-php73-php-bcmath rh-php73-php-pecl-apcu rh-php73-php-pecl-apcu-devel rh-php73-php-intl -y
# systemctl enable rh-php73-php-fpm
# systemctl start rh-php73-php-fpm
# systemctl enable nginx
# systemctl start nginx

For Ubuntu Install
# add-apt-repository ppa:ondrej/php
# apt-get update && apt-get -y upgrade && apt-get -y dist-upgrade
# apt install php5.6-cgi php5.6-mysql php5.6-curl php5.6-gd php5.6-imap php5.6-mcrypt php5.6-tidy php5.6-xmlrpc php5.6-xsl php5.6-mbstring php5.6-zip php5.6-cli
# apt install php7.1-cgi php7.1-mysql php7.1-curl php7.1-gd php7.1-imap php7.1-mcrypt php7.1-tidy php7.1-xmlrpc php7.1-xsl php7.1-mbstring php7.1-zip php7.1-cli
# apt install php7.2-cgi php7.2-mysql php7.2-curl php7.2-gd php7.2-imap php7.2-tidy php7.2-xmlrpc php7.2-xsl php7.2-mbstring php7.2-zip php7.2-cli

For Debian Install
# apt-get update
# apt-get -y install curl wget gnupg2 ca-certificates lsb-release apt-transport-https
# wget && apt-key add apt.gpg
# echo "deb $(lsb_release -sc) main" | tee /etc/apt/sources.list.d/php7.list
# apt-get update && apt-get -y upgrade && apt-get -y dist-upgrade
# apt-get -y install php7.1 php7.1-cgi php7.1-mysql php7.1-curl php7.1-gd php7.1-imap php7.1-mcrypt php7.1-tidy php7.1-xmlrpc php7.1-xsl php7.1-mbstring php7.1-zip php7.1-cli php7.1-common php7.2 php7.2-cgi php7.2-mysql php7.2-curl php7.2-gd php7.2-imap php7.2-tidy php7.2-xmlrpc php7.2-xsl php7.2-mbstring php7.2-zip php7.2-cli php7.2-common php7.3 php7.3-cgi php7.3-mysql php7.3-curl php7.3-gd php7.3-imap php7.3-tidy php7.3-xmlrpc php7.3-xsl php7.3-mbstring php7.3-zip php7.3-cli php7.3-common php7.4 php7.4-cgi php7.4-mysql php7.4-curl php7.4-gd php7.4-imap php7.4-tidy php7.4-xmlrpc php7.4-xsl php7.4-mbstring php7.4-zip php7.4-cli php7.4-common
# update-alternatives --set php /usr/bin/php7.3
# php -v

Now download the Virtualmin install script and run the install. The command shown below will install a minimal version of Virtualmin using the Nginx server instead of Apache which should consume less memory:

# wget
# sh -m -b LEMP

When you first log in to Virtualmin, it will run the Install Wizard. make sure to use Vultr’s DNS servers when it asks for a primary and secondary DNS. Also, under System Settings > Virtualmin Configuration click on SSL Settings and choose yes for “Request Let’s Encrypt certificate at domain creation time?” and “Redirect HTTP to HTTPS by default?” and save the changes. Next, go to Webmin -> Others -> PHP Configuration and edit the default PHP configuration being used so that users can upload larger files. This can be done by increasing the Maximum file upload size and Maximum HTTP POST size. Now go to Webmin -> Hardware -> System Time and configure your timezone and synchronize with a time server ( Then go back to your Vultr Control Panel and click on “Server Details” for your Server instance. Then click on “Settings” and change the Reverse DNS to your servers full host name (i.e.

Creating a Virtual Server

Within Virtualmin, click on “Create Virtual Server”. Enter the domain name and a user password and then click on “Enabled Features” and make sure that the box next to “Setup SSL website too?” is checked, then click on the “Create Server” button. Before the server will work, you need to add the domain to your DNS settings in your Vultr Control Panel. A sub-server can be created by clicking on “Create Virtual Server” and then selecting the sub-server button at the top of the page next to “New virtual server type”. Also a redirect can be created by going to Server Configuration > Website Redirects and clicking on the “Add a new website redirect” button, then adding “/” for the source URL path and the redirect URL for the destination. After creating a new Virtual server for your primary domain, create a mail alias by creating a new virtual and selecting ‘Alias’. Then go to Server Configuration > SSL Certificate and click the “Copy” buttons to copy it to all the services that it will be used for. Now go to Virtualmin > Email Settings > DomainKeys Identified Mail. You probably won’t have DKIM filter installed on your server. Virtualmin will give you an option to install it. Do it and then enable ‘Signing of outgoing mail’. Enter the current year for the selector and click on save. Add your primary domain with the “mail” prefix to the “additional domains to sign for” section (i.e. Also, make sure that your domain name is listed in there (i.e. You will also need to make sure that both ‘Signing of outgoing mail enabled?‘ and ‘Reject incoming email with invalid DKIM signature?‘ are set to yes. Next, go to Server Configuration > DNS Options under your domain name and make sure that the IP address isn’t repeated in ‘Allowed sender IPv4 addresses‘. Change “Action for other senders” to “Discourage”, “DMARC record enabled?” to “Yes”, and “DMARC policy for emails that fail SPF or DKIM” to “Quarantine email”. Last, go to Virtualmin > Email Settings > Mail Client Configuration and enable mail client autoconfiguration. You can set a default domain by logging into Virtualmin, choosing your desired domain from the drop-down on the left, then clicking Server Configuration -> Website Options, and setting “Default website for IP address” to “Yes”. You can also set the default PHP execution mode to FPM under System Settings -> Server Templates and selecting PHP Options from the drop-down list.

Configure Baikal CalDAV/CardDav Server used for Calander/Addressbook Syncing

In Virtualmin, create a new virtual server using the steps above which will be used to host the Baikal CalDAV/CardDAV server. Download the latest release here. Copy all of the files in the “html” folder of the zip file into the “public_html” folder of your virtual server. The rest of the files get copied into the parent folder. Make sure that the “Specific” folder is writable by your webserver process. Now you should be able to run the server installer by accessing this virtual server from a browser.

Configure Roundcube

In Virtualmin, click on “Install Scripts” and choose “Roundcube”. After it installs, add the CardDAV plugin manually by uncompressing it in the plugins folder and adding ‘carddav’ to the file. Until an official CalDAV Calendar plugin is developed, we will just have to go without a calendar for a while…. Set up the CardDAV plugin by having it connect to your Baikal CardDav server at Now you can test out your mail server configuration by going to If DKIM is failing then try editing /etc/opendkim.conf and make sure that the line beginning with ‘Socket’ has ‘inet:8891@localhost’ after it.

Configure Scheduled Backups

In Virtualmin, click on “Scheduled Backups” and click on the “Add a New Backup Schedule” button. Select the virtual servers and features that you want to backup. Next select your destination server and path. You can use “%Y-%m-%d” in the path to show the date. Last, you will need to select when the backup will run and then click on the “Save Schedule” button.

Network Booting LibreElec to Raspberry Pi’s from a Synology NAS

Work Environment

NAS: Synology DS216+II with DSM 6.1.7-15284

Netgear WNDR3700v2 Router Running Gargoyle Firmware version 1.10.0 or DD-WRT v3.0-r40559 std (08/06/19)

Raspberry Pi’s

Before you begin

Enable SSH on the NAS.

If you have a battery backup unit then enable UPS.

Download LibreElec image files for all architectures of Raspberry Pi’s on the network (i.e. RPi1, RPI3)

If your router acts as the DHCP server in your network then it will need to support network booting (most do not) if you want to continue to use it as the DHCP server, otherwise you will need to disable DHCP on your router and setup a DHCP server on your NAS. An alternative is to install a Linux firmware to your router if it’s possible (i.e. OpenWRT, DD-WRT, etc.) which is the scenario used for this guide.
Continue reading