How to Setup FastCGI Caching with Nginx on your VPS or Dedicated Server

A FastCGI module is present in Nginx. This module includes directives. Dynamic content that is served from the PHP back-end can be cached or stored using them. This will solve your problem and you won’t have to trouble yourself with additional page caching solutions and application-specific plugins.

Setting up FastCGI Caching on your VPS

First of all, you will need to setup and configure Nginx with PHP on your VPS. Now you will have to edit the Virtual Host configuration file for which you have to enable caching.

nano /etc/nginx/sites-enabled/vhost

Special note: consult HostAdvice’s  Best VPS hosting  page to find the leading web hosts in this category, including expert and user reviews.

Outside the server { }  directive, you will have to add these line to the top of the file:

fastcgi_cache_path /etc/nginx/cache levels=1:2 keys_zone=FASTCACHE:100m inactive=60m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";

You will see the “fastcachepath” directive, it states the location of the cache, size, memory zone name, the subdirectory levels, and the inactive timer.

While you are free to use any location on the hard disk but you need to be extremely careful while choosing the size, it needs to be less than the RAM of your vps and Swap combined. If the size exceeds this criterion then you will receive an error that says ‘Cannot allocate memory’.  The levels options in the purging section needs to be viewed – Nginx removes a cache if it is not accessed for the time stated by the ‘inactive’ option.

Hashing of the cache filenames are stated by the ‘fastcgicachekey’ directive. Based on its directive, an accessed file is encrypted with MD5 by Nginx.

Now you the location directive that passes PHP request has to be shifted to php5-fpm. You will need to add these lines in the “location ~ .php$ { }”:

fastcgi_cache FASTCACHE;
fastcgi_cache_valid 200 60m;

In the above lines, the ‘fastcgi_cache’ alludes to the memory zone name which has already been mentioned by us in the ‘fastcgicache_path’ directives and the cache is also stored in this area.

The cached objects, by default, are stored by Nginx for a duration that is specified by one of the headers provided here: X-Accel-Expires, Expires, Cache-Control.

In case these headers are missing, the default cache lifetime is specified by ‘fastcgicachevalid’ directive present in the above line. As per our configuration in the above lines, caching is done only the responses that posses a status code of 200.

Configuration test

Now a configuration test is to be done.

service nginx configtest

Reload Nginx if everything is OK

service nginx reload

Now you will see the vhost file looking like this:

fastcgi_cache_path /etc/nginx/cache levels=1:2 keys_zone=FASTCACHE:100m inactive=60m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
server {
    listen   80;
    root /usr/share/nginx/html;
    index index.php index.html index.htm;
    server_name yourdomainname.com;

    location / {
        try_files $uri $uri/ /index.html;
    }
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_pass unix:/var/run/php5-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_cache FASTCACHE;
        fastcgi_cache_valid 200 60m;
    }
}

Testing FastCGI Caching on your VPS

First you will need to create a PHP file that outputs a UNIX timestap.

/usr/share/nginx/html/test.php

Then insert the following:

<?php
echo time();
?>

Use your web browser or curl to request this file a number of times.

root@server:~# curl http://localhost/test.php;echo
1372986152
root@server:~# curl http://localhost/test.php;echo
1372986152
root@server:~# curl http://localhost/test.php;echo
1372986152

If you are lucky enough to see the same timestamp on all requests then caching is working in an appropriate manner.

Next, you will have to find the cache of this request by performing a recursive listing of the cache location.

root@vps:~# ls -lR /etc/nginx/cache/
/etc/nginx/cache/:
total 0
drwx------ 3 www-data www-data 60 Oct 28 18:53 e

/etc/nginx/cache/e:
total 0
drwx------ 2 www-data www-data 60 Oct 28 18:53 18

/etc/nginx/cache/e/18:
total 4
-rw------- 1 www-data www-data 117 Oct 28 18:53 b777c8adab3ec92cd43756226caf618e

If you wish to add an ‘X-Cache’ header to the response you can do this with the help of Nginx. This will indicate whether the cache was missed or hit.

This needs to be added above the server { } directive:

add_header X-Cache $upstream_cache_status;

Now see the new header by reloading the Nginx service and doing a verbose request with curl.

root@vps:~# curl -v http://localhost/test.php
* About to connect() to localhost port 80 (#0)
*   Trying 127.0.0.1...
* connected
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET /test.php HTTP/1.1
> User-Agent: curl/7.26.0
> Host: localhost
> Accept: */*
>
* HTTP 1.1 or later with persistent connection, pipelining supported
< HTTP/1.1 200 OK
< Server: nginx
< Date: Tue, 27 April 2017 09:10:45 GMT
< Content-Type: text/html
< Transfer-Encoding: chunked
< Connection: keep-alive
< X-Cache: HIT
<
* Connection #0 to host localhost left intact
1373035828* Closing connection #0

Setting Cache Exceptions

In some cases, like authentication, pages are required not to be cached. Based on variables like ‘requesturi’, ‘rquestmethod’, and ‘http_cookie we can exclude such contents from being cached.

The following is an example of configuration that should be used in server{ }context:

set $no_cache 0;
if ($request_method = POST)
{
    set $no_cache 1;
}
if ($query_string != "")
{
    set $no_cache 1;
}
if ($request_uri ~* "/(administrator/|login.php)")
{
    set $no_cache 1;
}
if ($http_cookie = "PHPSESSID")
{
    set $no_cache 1;
}

The following lines need to be put in  location ~ .php$ { } to apply the ‘$no_cache’ variable to appropriate derivatives:

fastcgi_cache_bypass $no_cache;
fastcgi_no_cache $no_cache;

 

The existing cache for requests related to the conditions set by us above are ignored by the ‘factcgicachebypass’ directive while if the stated requirements are fulfilled then the ‘fastcginocache’ stops the request from being cached.

Purging the Cache

The variables that we set for the ‘fastcgicachekey’ derivatives are the basis of the naming convention of the cache.

fastcgi_cache_key "$scheme$request_method$host$request_uri";

As per these variables, these would have been the actual values when “http://localhost/time/php” was requested by us:

fastcgi_cache_key "httpGETlocalhost/test.php";

The following string would be the output when this string is passed through the MD5 hashing:

9552f2a3f53b52db6409e47b57ff63c0

The filename of the cache will be formed by this. Since we have set “levels=1:2” for the subdirectories thus the first level of the directory will be named with the first character from the last of this MD5 string while the second level will have the last two characters after the first level.

Thus, the following will be the entire directory structure if this cache:

/etc/nginx/cache/e/18/ 9552f2a3f53b52db6409e47b57ff63c0

Now all you have to do is develop a purging script in any language of your wish based on this cache. To purge the cache of a POSTed URL a PHP script is provided below.

/usr/share/nginx/html/purge.php

Insert

<?php
$cache_path = '/etc/nginx/cache/';
$url = parse_url($_POST['url']);
if(!$url)
{
    echo 'Invalid URL entered';
    die();
}
$scheme = $url['scheme'];
$host = $url['host'];
$requesturi = $url['path'];
$hash = md5($scheme.'GET'.$host.$requesturi);
var_dump(unlink($cache_path . substr($hash, -1) . '/' . substr($hash,-3,2) . '/' . $hash));
?>

Now you will have to send a POST request to this file along with the URL to purge.

curl -d 'url=http://www.yourwesitename.com/test.php' http://yourwebsitename.com/purge.php

Now you will see an output of the script as True or False indicating if the cache was purged or not. You will have to restrict access and rule out this script from being cached.

Check out the top 3 VPS services:

HostArmada
$2.49 /mo
Starting price
Visit HostArmada
Rating based on expert review
  • User Friendly
    4.5
  • Support
    4.5
  • Features
    4.5
  • Reliability
    4.5
  • Pricing
    4.0
A2 Hosting
$2.99 /mo
Starting price
Visit A2 Hosting
Rating based on expert review
  • User Friendly
    4.5
  • Support
    4.0
  • Features
    4.5
  • Reliability
    4.8
  • Pricing
    4.0
Hostens
$0.90 /mo
Starting price
Visit Hostens
Rating based on expert review
  • User Friendly
    4.5
  • Support
    3.8
  • Features
    4.3
  • Reliability
    4.5
  • Pricing
    4.8

How to Install WordPress with Nginx & Redis

This is an easy-to-follow guide written to help you learn how to install WordPre
5 min read
Max Ostryzhko
Max Ostryzhko
Senior Web Developer, HostAdvice CTO

How to Install WordPress with Nginx & Redis on a CentOS VPS or Dedicated Server

This is an easy-to-follow guide written to help you learn how to install WordPre
5 min read
Eliran Ouzan
Eliran Ouzan
Web Designer & Hosting Expert

How to Harden the Nginx Web Server on your CentOS 7 Virtual Server or Dedicated Server

This article illustrates how to harden the Nginx web server on CentOS 7.
2 min read
Max Ostryzhko
Max Ostryzhko
Senior Web Developer, HostAdvice CTO

How to Configure Nginx and Apache on the same Ubuntu VPS or Dedicated Server

Nginx and Apache are great and powerful web servers. However, they both have dra
2 min read
Idan Cohen
Idan Cohen
Marketing Expert
HostAdvice.com provides professional web hosting reviews fully independent of any other entity. Our reviews are unbiased, honest, and apply the same evaluation standards to all those reviewed. While monetary compensation is received from a few of the companies listed on this site, compensation of services and products have no influence on the direction or conclusions of our reviews. Nor does the compensation influence our rankings for certain host companies. This compensation covers account purchasing costs, testing costs and royalties paid to reviewers.