Installing Nginx
Nginx has become the most popular web server software used on Linux servers, so it makes sense to use it rather than Apache. Although the official Ubuntu package repository includes Nginx packages, they’re often very outdated. Instead, I like to use the package repository maintained by Ondřej Surý that includes the latest Nginx stable packages.
First, add the repository and update the package lists:
sudo add-apt-repository ppa:ondrej/nginx -y
sudo apt update
There may now be some packages that can be upgraded, let’s do that now:
sudo apt dist-upgrade -y
Then install Nginx:
sudo apt install nginx -y
Once complete, you can confirm that Nginx has been installed with the following command:
nginx -v
ashley@pluto:~$ nginx -v
nginx version: nginx/1.20.0
Additionally, when visiting the Fully Qualified Domain Name (FQDN) pointing to your server’s IP address in the browser, you should see an Nginx welcome page.
Welcome to nginx
Now that Nginx has successfully been installed it’s time to perform some basic configuration. Out-of-the-box Nginx is pretty well optimized, but there are a few basic adjustments to make. However, before opening the configuration file, you need to determine your server’s CPU core count and the open file limit.
Enter the following command to get the number of CPU cores your server has available. Take note of the number as we’ll use it in a minute:
grep processor /proc/cpuinfo | wc -l
Run the following to get your server’s open file limit and take note, we’ll need it as well:
ulimit -n
Next, open the Nginx configuration file, which can be found at /etc/nginx/nginx.conf:
sudo nano /etc/nginx/nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
# multi_accept on;
}
http {
##
# Basic Settings
##
I’m not going to list every configuration directive but I am going to briefly mention those that you should change. If you would find it easier to see the whole thing at once, feel free to download the complete Nginx config kit now.
Start by setting the user to the username that you’re currently logged in with. This will make managing file permissions much easier in the future, but this is only acceptable security-wise when running a single user access server.
The worker_processes directive determines how many workers to spawn per server. The general rule of thumb is to set this to the number of CPU cores your server has available. In my case, this is 1.
The events block contains two directives, the first worker_connections should be set to your server’s open file limit. This tells Nginx how many simultaneous connections can be opened by each worker_process. Therefore, if you have two CPU cores and an open file limit of 1024, your server can handle 2048 connections per second. However, the number of connections doesn’t directly equate to the number of users that can be handled by the server, as the majority of web browsers open at least two connections per request. The multi_accept directive should be uncommented and set to on. This informs each worker_process to accept all new connections at a time, opposed to accepting one new connection at a time.
Moving down the file you will see the http block. The first directive to change is the keepalive_timeout which by default is set to 65. The keepalive_timeout determines how many seconds a connection to the client should be kept open before it’s closed by Nginx. This directive should be lowered as you don’t want idle connections sitting there for up to 65 seconds if they can be utilized by new clients. I have set mine to 15.
For security reasons you should uncomment the server_tokens directive and ensure it is set to off. This will disable emitting the Nginx version number in error messages and response headers.
Underneath server_tokens add the client_max_body_size directive and set this to the maximum upload size you require in the WordPress Media Library. I chose a value of 64m.
Further down the http block you will see a section dedicated to gzip compression. By default, gzip is enabled but you should tweak these values further for better handling of static files. First, you should uncomment the gzip_proxied directive and set it to any, which will ensure all proxied request responses are gzipped. Secondly, you should uncomment the gzip_comp_level and set it to a value of 5. This controls the compression level of a response and can have a value in the range of 1 – 9. Be careful not to set this value too high as it can have a negative impact on CPU usage. Finally, you should uncomment the gzip_types directive, leaving the default values in place. This will ensure that JavaScript, CSS, and other file types are gzipped in addition to the HTML file type.
That’s the basic Nginx configuration dealt with. Hit CTRL + X followed by Y to save the changes.
In order for Nginx to correctly serve PHP you also need to ensure the fastcgi_param SCRIPT_FILENAME directive is set, otherwise you will receive a blank white screen when accessing any PHP scripts. Open the fastcgi_params file:
sudo nano /etc/nginx/fastcgi_params
Ensure the following directive exists, if not add it to the file:
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
To save the fastcgi_params file, hit CTRL + X followed by Y.
You must restart Nginx for the changes to take effect. Before doing so, ensure that the configuration files contain no errors by issuing the following command:
sudo nginx -t
If everything looks OK, go ahead and restart Nginx:
sudo service nginx restart
ashley@pluto:~$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
ashley@pluto:~$ sudo service nginx restart
* Restarting nginx [ OK ]
ashley@pluto:~$
Install PHP 8.0
Just as with Nginx, the official Ubuntu package repository does contain PHP packages. However, they are not the most up-to-date. Again, I use one maintained by Ondřej Surý for installing PHP. Add the repository and update the package lists as you did for Nginx:
sudo add-apt-repository ppa:ondrej/php -y
sudo apt update
Then install PHP 8.0, as well as all the PHP packages you will require:
sudo apt install php8.0-fpm php8.0-common php8.0-mysql \
php8.0-xml php8.0-xmlrpc php8.0-curl php8.0-gd \
php8.0-imagick php8.0-cli php8.0-dev php8.0-imap \
php8.0-mbstring php8.0-opcache php8.0-redis \
php8.0-soap php8.0-zip -y
You’ll notice php-fpm in the list of packages being installed. FastCGI Process Manager (FPM) is an alternative PHP FastCGI implementation with some additional features that plays really well with Nginx. It’s the recommended process manager to use when installing PHP with Nginx.
After the installation has completed, confirm that PHP has installed correctly:
php-fpm8.0 -v
ashley@pluto:~$ php-fpm8.0 -v
PHP 8.0.13 (fpm-fcgi) (built: Nov 22 2021 09:50:43)
Copyright (c) The PHP Group
Zend Engine v4.0.13, Copyright (c) Zend Technologies
with Zend OPcache v8.0.13, Copyright (c), by Zend Technologies
Configure PHP 8.0 and PHP-FPM
Once Nginx and PHP are installed you need to configure the user and group that the service will run under. As mentioned in the series introduction, this setup does not provide security isolation between sites by configuring PHP pools, so we will run a single PHP pool under your user account. If security isolation between sites is required we do not recommend that you use this approach and instead use SpinupWP to provision your servers.
Open the default pool configuration file:
sudo nano /etc/php/8.0/fpm/pool.d/www.conf
Change the following lines, replacing www-data with your username:
user = www-data
group = www-data
listen.owner = www-data
listen.group = www-data
Next, you should adjust your php.ini file to increase the WordPress maximum upload size. Both this and the client_max_body_size directive within Nginx must be changed for the new maximum upload limit to take effect. Open your php.ini file:
sudo nano /etc/php/8.0/fpm/php.ini
Change the following lines to match the value you assigned to the client_max_body_size directive when configuring Nginx:
upload_max_filesize = 64M
post_max_size = 64M
Hit CTRL + X and Y to save the configuration. Before restarting PHP, check that the configuration file syntax is correct:
sudo php-fpm8.0 -t
ashley@server:~$ sudo php-fpm8.0 -t
[09-May-2021 09:07:00] NOTICE: configuration file /etc/php/8.0/fpm/php-fpm.conf test is successful
If the configuration test was successful, restart PHP using the following command:
sudo service php8.0-fpm restart
Now that Nginx and PHP have been installed, you can confirm that they are both running under the correct user by issuing the htop command:
htop
If you hit SHIFT + M, the output will be arranged by memory usage which should bring the nginx and php-fpm8.0 processes into view. You should notice a few occurrences of both nginx and php-fpm.
Both processes will have one instance running under the root user. This is the main process that spawns each worker. The remainder should be running under the username you specified.
top - 08:55:43 up 29 min, 1 user, load average: 0.00, 0.00, 0.00
Tasks: 97 total, 1 running, 94 sleeping, 2 stopped, 0 zombie
%Cpu(s): 0.0 us, 6.2 sy, 0.0 ni, 93.8 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 981.2 total, 528.4 free, 129.4 used, 323.4 buff/cache
MiB Swap: 0.0 total, 0.0 free, 0.0 used. 700.2 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
676 root 20 0 241232 35892 29620 S 0.0 3.6 0:00.11 php-fpm8.0
680 root 20 0 630404 28408 15544 S 0.0 2.8 0:00.58 snapd
675 root 20 0 29272 17952 10292 S 0.0 1.8 0:00.04 networkd-dispat
341 root 19 -1 51464 13312 12308 S 0.0 1.3 0:00.11 systemd-journal
760 ashley 20 0 241608 12916 6616 S 0.0 1.3 0:00.00 php-fpm8.0
761 ashley 20 0 241608 12916 6616 S 0.0 1.3 0:00.00 php-fpm8.0
888 root 20 0 13796 8916 7472 S 0.0 0.9 0:00.00 sshd
863 root 20 0 12176 7408 6484 S 0.0 0.7 0:00.00 sshd
566 systemd+ 20 0 90228 6056 5292 S 0.0 0.6 0:00.03 systemd-timesyn
998 ubuntu 20 0 13928 5992 4528 S 0.0 0.6 0:00.45 sshd
1096 ashley 20 0 58988 5596 3756 S 0.0 0.6 0:00.00 nginx
If not, go back and check the configuration, and ensure that you have restarted both the Nginx and PHP-FPM services.
Test Nginx and PHP
To check that Nginx and PHP are working together properly, enable PHP in the default Nginx site configuration and create a PHP info file to view in your browser. You are welcome to skip this step, but it’s often handy to check that PHP files can be correctly processed by the Nginx web server.
First, you need to uncomment a section in the default Nginx site configuration which was created when you installed Nginx:
sudo nano /etc/nginx/sites-available/default
Find the section which controls the PHP scripts.
# pass PHP scripts to FastCGI server
#
#location ~ \.php$ {
# include snippets/fastcgi-php.conf;
#
# # With php-fpm (or other unix sockets):
# fastcgi_pass unix:/run/php/php8.0-fpm.sock;
# # With php-cgi (or other tcp sockets):
# fastcgi_pass 127.0.0.1:9000;
#}
As we’re using php-fpm, we can change that section to look like this:
# pass PHP scripts to FastCGI server
location ~ \.php$ {
include snippets/fastcgi-php.conf;
# With php-fpm (or other unix sockets):
fastcgi_pass unix:/run/php/php8.0-fpm.sock;
}
Save the file by using CTRL + X followed by Y. Then, as before, test to make sure the configuration file was edited correctly.
sudo nginx -t
If everything looks okay, go ahead and restart Nginx:
sudo service nginx restart
Next, create an info.php file in the default web root, which is /var/www/html.
cd /var/www/html
sudo nano info.php
Add the following PHP code to that info.php file, and save it by using the same CTRL + X, Y combination.
<?php
phpinfo();
?>
Lastly, because you set the user directive in your nginx.conf file to the user you’re currently logged in with, give that user permissions on the info.php file.
sudo chown ubuntu info.php
Now, if you visit the info.php file in your browser, using the FQDN you set up in chapter 1, you should see the PHP info screen, which means Nginx can process PHP files correctly.
PHP info screen.
Once you’ve tested this, you can go ahead and delete the info.php file.
sudo rm /var/www/html/info.php
Top comments (1)
If you are a macOS user, ServBay.dev is worth to try. You don't need to spend some time or couple of days to setup anything. Just download it and you can use it immediately. You can run multiple PHP versions simultaneously and switch between them effortlessly.
Honestly, this tool has greatly simplified my PHP development and is definitely worth trying!