Configuring Nginx for PHP web applications

Nginx and PHP FastCGI Process Manager (FPM) are often used side by side for PHP applications. In such a setting, Nginx will be the first point of contact for incoming HTTP requests, acting as a reverse proxy server for the PHP FastCGI Process Manager.

The PHP FastCGI Process Manager then interprets the HTTP requests that it receives from Nginx and runs the PHP scripts for generating the corresponding HTTP responses for Nginx to return back to the HTTP client.

This post discusses a set of configurations that you can use for configuring Nginx for your PHP web applications.

Nginx configurations for PHP web applications

Suppose you have:

  • the domain names example.com and www.example.com that are mapped to the IP address of the server where your Nginx installation is running from,
  • the directory /var/www/example.com on your server that contains the PHP scripts and / or static files for your application, and
  • the PHP FastCGI Process Manager running in the same machine as your Nginx installation and listening for requests via the unix socket unix:/run/php/php7.0-fpm.sock.

You can configure your Nginx web server for your PHP application with the following configurations:

server {
        listen   80;
        server_name example.com www.example.com;
        root /var/www/example.com;
       
        index index.php;

        location / {
                try_files $uri $uri/ /index.php?$args;
        }

        location ~ \.php$ {
                #NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
                include fastcgi.conf;
                fastcgi_pass unix:/run/php/php7.0-fpm.sock;
                fastcgi_buffers 16 16k;
                fastcgi_buffer_size 32k;
        }
}

What does the server_name and listen directives tell Nginx?

The server_name directive along with the listen directive instructs Nginx to handle HTTP GET requests directed at either http://example.com or http://www.example.com to take the instructions specified by this server block.

What does the root directive tells Nginx?

The root directive tells Nginx to look for files inside the /var/www/example.com directory to serve incoming HTTP GET requests. With this configuration, Nginx will map requests made to:

  • http://example.com/images/logo.png into the file path /var/www/example.com/images/logo.png.
  • http://example.com/contact.html into the file path /var/www/example.com/contact.html
  • http://example.com/about/us.html into the file path /var/www/example.com/about/us.html

What does the index directive tells Nginx?

The index directive tells Nginx that whenever a HTTP GET request is made to a directory inside the directory specified by the root directive, it should attempt to redirect the request to index.php from that directory. For this configuration, Nginx will map requests made to http://example.com/ into http://example.com/index.php. Since Nginx can only be sure that HTTP requests made to http://example.com/ is hitting the root directory, the index directive only takes effect for such HTTP requests.

Nginx uses the configurations inside the "location /" block to handle HTTP requests with urls like the following:

  • http://example.com/about
  • http://example.com/images
  • http://example.com/start-here
  • http://example.com/tools

This is because these urls could refer to files within the server file system, hence the index directive is not applied for such cases.

What does the "location /" block tells Nginx?

In this set of configurations, any HTTP request that have url that does not end with .php will be handled by Nginx according to the instruction in the "location /" block. For example, Nginx will use the configuration in the "location /" block to handle HTTP requests with the following urls:

  • http://example.com/images/logo.png
  • http://example.com/contact.html
  • http://example.com/about/us.html

Inside the "location /" block, the try_files directive tells Nginx to:

  • Try mapping the incoming HTTP request to a file path on the server file system.
  • Try mapping the incoming HTTP request to a directory path on the server, if the file path does not point to any file on the server.
  • Make an indirect request to the /index.php along any query string variables (captured by the $args Nginx variable), if the directory path does not point to any directory on the server. This will cause Nginx to handle the request with the instructions inside the "location ~ \.php$" block.

What does the "location ~ \.php$" block tells Nginx?

The execution of PHP scripts is made possible by the "location ~ \.php$" block. The "location ~ \.php$" block tells Nginx that whenever a HTTP request with a url ending with a .php extension, Nginx should handle the request with directives contained in this block.

Inside the "location ~ \.php$" block, the include directive tells Nginx to take the configurations defined inside the fastcgi.conf file located at the Nginx installation root.

The fastcgi.conf file describes the incoming HTTP request to the PHP FastCGI Process Manager via several fastcgi_param directive statements.

The fastcgi_pass directive shows Nginx the channel to communicate with the PHP FastCGI Process Manager. In this case, Nginx will communicate with PHP FastCGI Process Manager via the unix socket located at /run/php/php7.0-fpm.sock on the same machine. If the PHP FastCGI Process manager resides on another machine, you should replace /run/php/php7.0-fpm.sock with an address (for eg. 192.168.1.105) and port number (for eg. 9000):

fastcgi_pass 192.168.1.105:9000;

Note that if your PHP FastCGI Process Manager is on a separate machine, the directory /var/www/example.com must exist on the file system of machine as well. This is because the value from the root directive is passed over to the PHP FastCGI Process Manager via one of the fastcgi_param inside the fastcgi.conf file.

The fastcgi_buffers and fastcgi_buffer_size configure the way responses from the PHP FastCGI Process Manager are buffered.

Intuitions to developing your PHP application with this set of Nginx configurations

With this set of Nginx configurations applied, HTTP requests with urls not ending with .php will be directed to the /var/www/example.com/index.php file.

Implementing request dispatcher logic from /var/www/example.com/index.php

The PHP script /var/www/example.com/index.php is the starting point for implementing the request dispatcher based on the front controller pattern.

Getting the request uri with PHP

Since the HTTP request uri is passed over to PHP FastCGI Process Manager, we can use the request uri as one of the decision points in the generation of HTTP responses. Inside /var/www/example.com/index.php or any PHP scripts that are included afterwards, we can get the request uri from the $_SERVER['REQUEST_URI'] variable.

For example, the $_SERVER['REQUEST_URI'] returns:

  • /about for http://example.com/about
  • /about/me for http://example.com/about/me
  • /search?terms=abc for http://example.com/search?terms=abc
  • /start-here for http://example.com/start-here

Note that since query strings are included after the request uri, you may want to strip any query strings from $_SERVER['REQUEST_URI'] before performing uri parsing:

$clean_uri = strtok($_SERVER["REQUEST_URI"], '?');

Getting the HTTP method with PHP

The other variable to inspect for request dispatching is the HTTP method. You can get the HTTP method from $_SERVER['REQUEST_METHOD'].

Using a micro framework

Alternatively, instead of implementing the request dispatcher logic with $_SERVER['REQUEST_URI'] and $_SERVER['REQUEST_METHOD'], you can use the Slim micro framework within /var/www/example.com/index.php to build up your PHP web application quickly.

Requesting for PHP scripts directly

Another way of creating your PHP application is to craft the HTTP request to run PHP scripts directly. This way of development is usually used for building the admin portal of your web application. For example, the Dashboard in WordPress is realised mostly by calls made to PHP scripts directly. For example, along with the HTTP GET method, the request uri:

  • /wp-admin/edit.php will result in WordPress returning the table of posts in your blog.
  • /wp-admin/post-new.php will result in WordPress presenting a form for you to add a new blog post.
  • /wp-admin/upload.php will result in WordPress presenting you with the Media Library interface for you to have a glimpse of the image,
    audio and video files that you had uploaded to your blog; along with options to upload new ones, edit or delete existing ones.

About Clivant

Clivant a.k.a Chai Heng enjoys composing software and building systems to serve people. He owns techcoil.com and hopes that whatever he had written and built so far had benefited people. All views expressed belongs to him and are not representative of the company that he works/worked for.