| |

How to set up Nginx FastCGI Page Cache with WordPress.

Nginx FastCGI cache is a feature of the Nginx web server that enables the caching of dynamic content generated by FastCGI applications such as PHP. By caching the dynamic content, Nginx can serve the content directly to visitors as a static page so that the same dynamic request does not have to be processed over and over again, thus minimizing server load and handling large numbers of page views without crashing.

By utilizing both the Nginx FastCGI cache and Redis object cache together, you can achieve an optimized caching strategy that leverages the strengths of both mechanisms. By implementing these optimization techniques, you can provide your visitors with lightning-fast browsing experiences while improving your website’s SEO.

This step-by-step guide will walk you through the process of configuring Nginx with FastCGI cache to speed up your WordPress website.

In this scenario, we assume an Nginx server hosting multiple WordPress sites, as we outlined in this tutorial. While it is possible to create separate cache zones for each WordPress site, we’ll stick with one cache zone here that can be shared by all websites which is easy to set up and requires relatively little configuration. A major drawback of this approach is that when the cache for one of the sites needs to be flushed (e.g. because something has changed on a page) the entire cache is flushed, including the sites where nothing has changed. In one of the next tutorials, we will dig further into the process of assigning separate cache zones to sites on a Nginx server with multiple virtual hosts.

The two main directives in our FastCGI cache configuration are “fastcgi_cache_path” and “fastcgi_cache_key” which are both placed in the “http” context. In principle, the “fastcgi_cache_key” directive can also be set in the server or location, but for the basic configuration, we will keep the “http” context. If necessary, this directive can always be overwritten in another context.

In this tutorial, we assume you are working with Ubuntu and you are logged in as root, so switch to root user if you are not already.

sudo -i

Create a new file “fcgi-caching.conf” in the in the /etc/nginx/conf.d directory.

vi /etc/nginx/conf.d/fcgi-caching.conf

And add the following content:

fastcgi_cache_path /var/run/nginx-wordpress levels=1:2 keys_zone=WORDPRESS:100m max_size=512m inactive=60m use_temp_path=off;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;

By placing this configuration file in the “/etc/nginx/conf.d” folder, we ensure that it is available server-wide. So every site (virtual host) on this server can use the “key_zone” that we will name “WORDPRESS”. Below we list the directives used and their functions.

  • The “fastcgi_cache_path” directive specifies the location of the cache and the cache parameters. To take full advantage of page caching and provided your system has sufficient RAM, it is highly recommended that you use a RAM disk for the site to ensure the highest possible speed. In most Linux distributions, “/var/run” is already available as a ramdisk, including Ubuntu and therefore that is the location we are going to use to create our cache directory. We have chosen here to call the directory “nginx-wordpress,” but you are free to choose another name.
  • The “keys_zone” attribute defines the “WORDPRESS” cache and the size of the shared memory zone which is set here to “100m” (100MB) which is sufficient for about 800,000 keys (1MB zone can store data for about 8,000 keys).
  • The “max_size” field indicates the maximum size of the actual cache on disk which in our case is set to “512m” (512MB). If you are using ramdisk keep in mind that Ubuntu allocates on average only 20% of the available memory to “/var/run/”, so when determining “max_size” you should build in a safe margin and be sure not to exceed the available memory. To check what is allocated on your system run the command “df -h /var/run/”.
  • The “inactive” attribute tells Nginx when to purge data from the cache. This example uses a one-hour limit, indicated by “inactive=60m”. Cache contents that have not been accessed during this period are deleted.
  • The “use_temp_path=off” directive tells Nginx to put its temporary files in the same folder as the cache, instead of using a separate folder.
  • The “fastcgi_cache_key” directive defines the key format. Note that this directive can only be declared once otherwise Nginx will complain with “nginx: [emerg] “fastcgi_cache_key” directive is duplicate” and won’t start!
  • The “fastcgi_ignore_headers” disables the processing of certain response header fields that could adversely affect caching.

In accordance with the above configuration, create the directory that Nginx will use to store the generated cache (cache_location).

mkdir /var/run/nginx-wordpress

To optimize the operation and performance of FastCGI Cache, it is necessary to add some additional directives to the “fcgi-caching.conf” file.

Open the file.

vi /etc/nginx/conf.d/fcgi-caching.conf

Add the following code:

fastcgi_cache_lock on;
fastcgi_cache_use_stale error timeout invalid_header updating http_500 http_503;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_keep_conn on;
fastcgi_connect_timeout 30s;
fastcgi_read_timeout 30s;
fastcgi_cache_background_update on;

Below is an overview and features of the added directives.

  • By enabling “fastcgi_cache_lock”, only one request at a time will be allowed to populate a new cache element, identified according to the fastcgi_cache_key directive by passing a request to a FastCGI server. Other requests of the same cache element will wait for a response in the cache or the cache lock for this element will be released, until the time set by the fastcgi_cache_lock_timeout directive (which is 5 sec. by default).
  • The “fastcgi_cache_use_stale” directive defines in which cases pages are served from the cache in case the FastCGI server is not functioning properly and errors occur.
  • Determining the proper “fastcgi buffers” and “fastcgi_buffer_size” is rather cumbersome and will be covered in more detail in a possible future article, but for now, we’ll leave it at what we think are the best parameters.
  • By default, FastCGI will close a connection right after sending the response. Setting the value of the “fastcgi_keep_conn” directive to “on” will instruct FastCGI to keep the connections open. This will increase performance since the socket between Nginx and PHP-FPM stays open after the request has been processed. Therefore the time spent opening the socket is saved.
  • The “fastcgi_connect_timeout” directive defines a timeout for establishing a connection with a FastCGI server.
  • The “fastcgi_read_timeout” directive defines the timeout for reading a response from the FastCGI server. The timeout is set only between two consecutive read operations, not for sending the entire response. If the FastCGI server does not send anything within this time, the connection is disconnected. The default time is 60s but we bring it down to 30s here.
  • If enabled, the “fastcgi_cache_background_update” allows a subrequest to be started in the background to update an expired cache entry while returning an old cache response to the client. This option is disabled by default but is necessary to allow the usage of a stale cached response when it is being updated.

The full contents of our “fcgi-caching.conf” file now look as follows:

fastcgi_cache_path /var/run/nginx-cache/wordpress levels=1:2 keys_zone=WORDPRESS:100m max_size=512m inactive=60m use_temp_path=off;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
fastcgi_cache_lock on;
fastcgi_cache_use_stale error timeout invalid_header updating http_500 http_503;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_keep_conn on;
fastcgi_connect_timeout 30s;
fastcgi_read_timeout 30s;
fastcgi_cache_background_update on;

For WordPress and WooCommerce to work properly, it is important to skip caching in specific situations or on certain pages. For this, we need to create a new snippet that can easily be included in a particular server block.

Create and open the new file which we will call “wp-skip-cache.conf”.

vi /etc/nginx/snippets/wp-skip-cache.conf

Add the following code:

# Set the variable "skip_cache" to "off
set $skip_cache 0;

# POST requests and urls with a query string should always go to PHP
if ($query_string != "") {
  set $skip_cache 1;
}

# Don't cache uris containing the following segments
if ($request_uri ~* "(/wp-admin/|/xmlrpc.php|/wp-(app|cron|login|register|mail).php|wp-.*.php|/feed/|index.php|wp-comments-popup.php|wp-links-opml.php|wp-locations.php|sitemap(_index)?.xml|[a-z0-9_-]+-sitemap([0-9]+)?.xml)") {
  set $skip_cache 1;
}

# Don't cache uris containing the following segments (woocommerce)
if ($request_uri ~* "/store.*|/cart.*|/my-account.*|/checkout.*|/addons.*") {
         set $skip_cache 1;
}

if ( $arg_add-to-cart != "" ) {
      set $skip_cache 1;
}

# Don't use the cache for logged in users or recent commenters
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
  set $skip_cache 1;
}

# Stop caching as soon as a visitor adds something to cart
if ( $cookie_woocommerce_items_in_cart = "1" ) {
    set $skip_cache 1;
}

The comments explain what the code is for and when it is activated or caching is skipped.

To activate page caching for a particular site, it is necessary to modify the relevant Nginx configuration file.

vi /etc/nginx/sites-available/example.com
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server_name example.com;

    ssl_certificate /etc/acme/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/acme/live/example.com/privkey.pem;

    include global/ssl.conf;

    root /var/www/virtual/example.com/htdocs;
    index index.php index.html index.htm;

    access_log /var/log/nginx/example.com-access.log;
    error_log /var/log/nginx/example.com-error.log;

    include snippets/expires.conf;
    include snippets/wp-skip-cache.conf;

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

    location ~ \.php$ {
      fastcgi_pass unix:/run/php/php8.2-fpm.sock;
      include global/fastcgi-php.conf;
      include global/security-headers.conf;
      fastcgi_cache_bypass $skip_cache;
      fastcgi_no_cache $skip_cache;
      fastcgi_cache WORDPRESS;
      fastcgi_cache_valid 404 1m;
      fastcgi_cache_valid 60m;
      add_header X-FastCGI-Cache $upstream_cache_status;
      add_header Cache-Control "no-cache";
      add_header x-cache-enabled "true";
    }

    location ~ /\.ht {
      deny all;
    }
}

The code highlighted in red should be added.

Now that Nginx is configured, the relevant WordPress instance should also be made aware that FastCGI Cache is enabled and that the cache should be cleared after a change in content, such as pages and posts but also layout changes. For this, we use the WordPress plugin “Nginx Cache” by Till Krüss.

The installation of the plugin will be done using WP CLI here, but it can also be done in the WP admin if necessary.

Go to the root directory of the WordPress instance for which you want to install the plugin and run the following command:

wp plugin install nginx-cache --allow-root

After installation, “auto purge” must be set and the cache location specified for the plugin to work correctly.

wp option update nginx_auto_purge 1 --allow-root &&\
wp option update nginx_cache_path '/var/run/nginx-cache/' --allow-root

Finally, we need to activate the plugin.

wp plugin activate nginx-cache --allow-root
Plugin 'nginx-cache' activated.
Success: Activated 1 of 1 plugins.

If all went well, you now have a WordPress site that will perform significantly faster with FastCGI cache, even with a high number of visitors.

Similar Posts