Filter query string for Redis-Nginx cache

In EasyEngine the page cache is being stored and retrieved by Nginx from Redis. It first creates a cache key and stores the HTML content as value.

By default in EasyEngine, if the request comes with query parameter(s) then Nginx skips caching and sends the request directly to PHP. This mechanism works fine for the smaller sites but in the case of sites with high traffic, this creates performance issues.

While analyzing logs for the same, I found that number of requests is hitting the home page with utm_* queries with different values most of the time. We also wanted a mechanism where we can cache search pages, product-related pages, etc.

Writing if conditions won’t work as we also wanted to cache with multiple query parameters.

⚠️ This method is experimental.

Example

Allowed Parameters: “q”, “s”

Request: https://example.com/?q=12&utm_source=instagram&s=india

Cache-Key: example.com_page:httpsGETexample.com/?q=12&s=india

As you can see above the cache key generated with only q and s parameters ignoring utm_source.

Nginx Configuration

0. Take backup of your current Nginx configurations.

1. Comment out following block in Nginx configuration file

if ($query_string != "") {
    set $skip 1;
}

Path of the Nginx configuration file in EasyEngine is: /opt/easyengine/sites/example.com/config/nginx/conf.d/main.conf

2. Add following Lua script in top of the PHP location block location ~ .php$

set $has_args '';

set_by_lua $request_uri_without_args 'return string.gsub(ngx.var.request_uri, "?.*", "")';

set_by_lua $cleaned_args '
local allow = {"p", "q", "s"}
local args, err = ngx.req.get_uri_args()
local c_args = {}

for arg, arg_value in pairs(args) do
    for _, allowed_arg in ipairs(allow) do
        if arg == allowed_arg then
            if type(args[allowed_arg]) ~= "boolean" then
                table.insert(c_args, arg .. "=" .. string.gsub(args[allowed_arg], "%s+", ""))
                ngx.var.has_args = "?"
            else
                table.insert(c_args, arg)
                ngx.var.has_args = "?"
            end
        end
    end
end

return table.concat(c_args, "&")
';

Update allow { "p", "q", "s" } as per your needs. Be sure that not mentioning the required parameters here may break the site functionality.

3. Update the cache key as in the following code:

set $key "example.com_page:http$request_method$host$request_uri_without_args$has_args$cleaned_args";
if ($HTTP_X_FORWARDED_PROTO = "https") {
    set $key "example.com_page:https$request_method$host$request_uri_without_args$has_args$cleaned_args";
}

4. Restart Nginx

Debugging

Get Cache-key in the response header

Add following in the PHP location block.

more_set_headers 'X-CACHE-KEY $key';

Redis-Cli

To view the keys stored in the Redis for page cache you can use

redis-cli keys "*_page*"

Lua code

Compile Nginx image with debug flag. Here‘s the documentation.