Improving nginx Proxy + Fastcgi Page Caching Skip Cache Reasons

Many nginx users nowadays are enjoying the benefits of server side caching with a reverse proxy cache or fastcgi cache (this is what Kinsta use). I have the pleasure of working with a lot of these server configurations and sometimes you get some undesired caching behavior that you need to debug in the nginx virtual host!

If you want to control cache times dynamically for nginx see this post

Most nginx caching configurations do not provide a header for the reason why the page cache was skipped. The ones that do only have a singular reason but sometimes there can be multiple triggers that prevent the specific page (URL or URI) from being cached. This tutorial will show you how to add multiple reasons for skipping the nginx page cache. You will need access to your nginx virtual host or have your hosting provider make these changes. This is for WordPress but you can apply the same technique to any Content Management System (CMS).

Improving nginx Proxy and Fastcgi Page Caching Skip Cache Reasons

Here is a traditional nginx virtual host snippet with fastcgi caching enabled without any cache skip reason headers added for WordPress.

# cache by default
set $skip_cache 0;

# POST requests and urls with a query string should always go to PHP
if ($request_method = POST) {
	set $skip_cache 1;
}
if ($query_string != "") {
	set $skip_cache 1;
}
# Don't cache uris containing the following segments
if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml") {
	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;
}

location ~ \.php$ {
	try_files $uri =404;
	# add cache status
	add_header WP-Bullet-Fastcgi-Cache $upstream_cache_status;
	include fastcgi_params;
	fastcgi_pass unix:/run/php/php7.2-fpm.sock;
	fastcgi_split_path_info ^(.+\.php)(.*)$;
	fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
	fastcgi_cache_bypass $http_secret_header $skip_cache;
	fastcgi_no_cache $skip_cache;
	fastcgi_cache WORDPRESS;
	fastcgi_cache_valid 404      1m;
	fastcgi_cache_valid  60m;
}

Here is a traditional nginx virtual host snippet with fastcgi caching enabled and includes the skip cache reason which is really useful for debugging!

# cache by default
set $skip_cache 0;

# POST requests and urls with a query string should always go to PHP
if ($request_method = POST) {
	set $skip_cache 1;
	set $skip_reason "POST";
}
if ($query_string != "") {
	set $skip_cache 1;
	set $skip_reason "QueryString";
}
# Don't cache uris containing the following segments
if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml") {
	set $skip_cache 1;
	set $skip_reason "URI";
}
# 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;
	set $skip_reason "Cookie";
}

location ~ \.php$ {
	try_files $uri =404;
	# add cache status
	add_header WP-Bullet-Fastcgi-Cache $upstream_cache_status;
	# add the cache skip reason if relevant
	add_header WP-Bullet-Skip $skip_reason;
	include fastcgi_params;
	fastcgi_pass unix:/run/php/php7.2-fpm.sock;
	fastcgi_split_path_info ^(.+\.php)(.*)$;
	fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
	fastcgi_cache_bypass $http_secret_header $skip_cache;
	fastcgi_no_cache $skip_cache;
	fastcgi_cache WORDPRESS;
	fastcgi_cache_valid 404      1m;
	fastcgi_cache_valid  60m;
}

According to the configuration above, it is always the last skip reason that will go inside of the WP-Bullet-Skip header. In order to get multiple skip cache reasons we need to concatenate (join together) these variables. That is possible using this technique which looks like this "${skip_reason}-POST". This concatenates the variables together so we can see multiple reasons for the nginx cache being skipped!

# cache by default
set $skip_cache 0;
# set default empty skip reason
set $skip_reason "";

# POST requests and urls with a query string should always go to PHP
if ($request_method = POST) {
	set $skip_cache 1;
	set $skip_reason "${skip_reason}-POST";
}
if ($query_string != "") {
	set $skip_cache 1;
	set $skip_reason "${skip_reason}-QueryString";
}
# Don't cache uris containing the following segments
if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml") {
	set $skip_cache 1;
	set $skip_reason "${skip_reason}-URI";
}
# 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;
	set $skip_reason "${skip_reason}-Cookie";
}

location ~ \.php$ {
	try_files $uri =404;
	# add cache status
	add_header WP-Bullet-Fastcgi-Cache $upstream_cache_status;
	# add the cache skip reason if relevant
	add_header WP-Bullet-Skip $skip_reason;
	include fastcgi_params;
	fastcgi_pass unix:/run/php/php7.2-fpm.sock;
	fastcgi_split_path_info ^(.+\.php)(.*)$;
	fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
	fastcgi_cache_bypass $http_secret_header $skip_cache;
	fastcgi_no_cache $skip_cache;
	fastcgi_cache WORDPRESS;
	fastcgi_cache_valid 404      1m;
	fastcgi_cache_valid  60m;
}

As always make sure the nginx virtual host is valid

nginx -t

If you see everythig is OK then reload nginx

sudo service nginx reload

Sources

Merging Variables in nginx

2 thoughts on “Improving nginx Proxy + Fastcgi Page Caching Skip Cache Reasons”

  1. Thank you very much, despite this is an old thread, but it is the only one that helped me set up proper skip reasons, really appreciate it. keep up the good work.

Comments are closed.