Migrating from Apache to Nginx on FreeBSD

In this article I will tell you how I’ve migrated my servers running Apache+PHP to Nginx+PHP-fpm without diying the process.


[Skip Intro]

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


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
nginx port configuration
The default options are fine, but take a look at the options for any feature you could want


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
php port configuration
Make sure the FPM option is selected

If FPM isn’t selected, select it, then run:

[/usr/ports/lang/php74]# make install clean

The configuration


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


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 cores
  • client_max_body_size: should match the values of post_max_size and upload_max_size in php.ini.
  • root: equals DocumentRoot 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.

Gonzalo Rivero
I am Gonzalo, I live in Salta, a city located in the NW of Argentina. I play the guitar and a little harmonica. I also like to bike.


Please enter your comment!
Please enter your name here

Latest articles

You might also likeRELATED

Bash scripting(III)

This is the third article of a series focused in Gnu Bash scripting. On the first article we’ve just created a simple script with...

Bash scripting(II)

This is the second article of a series focused in Gnu Bash scripting. On the first bash scripting article we've just created the most...

Bash scripting(I)

This is the first article of a series focused in Gnu Bash scripting. It's not a complete course on bash programing, but at the...