In this article I will tell you how I’ve migrated my servers running Apache+PHP to Nginx+PHP-fpm without diying the process.
Scenario
In 2020, during the first days of the pandemic, we had a meeting in preparation for the upcoming quarantine. The plan was to continue moving all of our presential students to full remote education. I’ve asked how many students extra should I expect and they said about the double. Next, my suggestion was just to duplicate the hardware resources (ram & cpu cores) because:
- luckily I have enough room -in terms of hardware resources- for that kind of growing.
- the quarantine will be over in just two weeks, a month at most. Then our students will back to presential and I’ll get back those extra resources.
During the first two weeks of the original quarantine I had to increase the hardware resources more and more (but not duplicating them) and that solution proved insufficient. After the first month, with the exams closer every day, and the covid19 crisis menacing to extend even to summer, I had to think of a real solution. Also this solution needs to be done with the less possible downtime… we had enough moodle crashes already.
Again, lucky I’ve still have a couple of Gbs of RAM and CPU cores available. I’ve set up a tiny new VM (1 core and 1gb RAM) with a copy of one of my production moodles, to test things until it worked. Once I get the settings that do it, I could made the change with not downtime. The final change consists on shutdown apache and start nginx
The installing
Nginx
If you read some of my previous posts in FreeBSD I prefer the ports over the binary packages, so to install nginx run:
# cd /usr/ports/www/nginx
# make install clean
Php-fpm
The default way to run php code inside Apache is enabling the mod_php module. There isn’t (at least that I know) a nginx loadable module for PHP, so you need to enable fastCGI Process Manager. If you installed PHP with the default options, you probably already have it, but double check:
[/usr/ports/www/nginx]# cd ../../lang/php74
[/usr/ports/lang/php74]# make config
If FPM isn’t selected, select it, then run:
[/usr/ports/lang/php74]# make install clean
The configuration
PHP-Fpm
Create, if not exist the file /usr/local/etc/php-fpm.d/www.conf my copying www.conf.default and then edit:
[/usr/ports/lang/php74]# cd /usr/local/etc/php-fpm.d/
[/usr/local/etc/php-fpm.d/]# cp www.conf.default www.conf
[/usr/local/etc/php-fpm.d/]# ee www.conf
Scroll down to the relevant options:
user/group
: should be the same user and group as apache, www for me.listen
: as I’m serving php only locally, I’m using an unix socket:/var/run/php-fpm.sock
;pm
:dynamic
is fine, but you could need to tweak and tune this parameter. Take a look at the comments in the file.
Finally, let’s enable and start php-fpm:
[/usr/local/etc/php-fpm.d/] /usr/local/etc/rc.d/php-fpm enable
[/usr/local/etc/php-fpm.d/] /usr/local/etc/rc.d/php-fpm start
Nginx
The nginx.conf file could be as big (or been splitted in as many parts as) as the httpd.conf from apache. In special if you have several VirtualHosts, the relevant options are (at least to me where) :
user
: the same user as the apache process, in example, www.worker_process
: this should match the number of CPU coresclient_max_body_size
: should match the values ofpost_max_size
andupload_max_size
in php.ini.root
: equalsDocumentRoot
from your VirtualHost in apache httpd.conf, i.e. /usr/local/www/- Add the next section to tell nginx how to send your php code to php-fpm service:
location ~ [^/]\.php(/|$) {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_index index.php;
fastcgi_pass unix:/var/run/php-fpm.sock;
include fastcgi_params;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_read_timeout 120;
fastcgi_send_timeout 120;
}
The other options in the nginx.conf example file are pretty much self-explanatory. Of course, there are a lot of other things you can tweak, but this would do the magic.
Finally we can enable nginx, stop apache and start nginx (in that order or nginx would be able to listen in http/https ports):
# /usr/local/etc/rc.d/nginx enable
# /usr/local/etc/rc.d/apache24 stop
# /usr/local/etc/rc.d/nginx start
If something goes wrong
Notice that we didn’t disable apache yet. If something goes wrong just stop nginx and start apache24 that you know that it was already working fine:
# /usr/local/etc/rc.d/apache24 stop ; /usr/local/etc/rc.d/nginx start
When you are sure that everything is working as expected, you can disable apache.