Nginx Cache – Debugging High Number of Cache Misses

cachenginxreverse-proxy

My proxy cache path is set to a very high size

proxy_cache_path  /var/lib/nginx/cache  levels=1:2   keys_zone=staticfilecache:180m  max_size=700m;

and the size used is only

sudo du -sh *
14M cache
4.0K    proxy

Proxy cache valid is set to

proxy_cache_valid 200 120d;

I track HIT and MISS via

add_header X-Cache-Status $upstream_cache_status;

Despite these settings I am seeing a lot of MISSes. And this is for pages I intentionally ran a cache warmer an hour ago.

How do I debug why these MISSes are happening? How do I find out if the miss was due to eviction, expiration, some rogue header etc? Does Nginx provide commands for this?

Edit: Full config

    # at http level
    proxy_cache_path  /var/lib/nginx/cache  levels=1:2 inactive=400d keys_zone=staticfilecache:180m  max_size=700m;
    proxy_temp_path /var/lib/nginx/proxy;
    proxy_connect_timeout 30;
    proxy_read_timeout 120;
    proxy_send_timeout 120;
    #prevent header too large errors
    proxy_buffers 256 16k;
    proxy_buffer_size 32k;
    #httpoxy exploit protection
    proxy_set_header Proxy "";

    # at server level 
    add_header Cache-BYPASS-Reason $skip_reason;

    # define nginx variables
    set $do_not_cache 0;
    set $skip_reason "";
    set $bypass 0;

    # security for bypass so localhost can empty cache
    if ($remote_addr ~ "^(127.0.0.1|Web.Server.IP)$") {
        set $bypass $http_8X0;
    }

    # skip caching WordPress cookies
    if ($http_cookie ~* "comment_author_|wordpress_(?!test_cookie)|wp-postpass_" ) {
        set $do_not_cache 1;
        set $skip_reason Cookie;
    }

    # Don't cache URIs containing the following segments
    if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php") {
        set $skip_cache 1;
        set $skip_reason URI;
    }

    # https://guides.wp-bullet.com/how-to-configure-nginx-reverse-proxy-wordpress-cache-apache/
    location / {
            proxy_pass http://127.0.0.1:8000;

            proxy_set_header X-Real-IP  $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto https;
            proxy_set_header X-Forwarded-Port 443;
            proxy_set_header Host $host;
            proxy_set_header Accept-Encoding "";

            # may need to comment out proxy_redirect if get login redirect loop
            proxy_redirect off;

            proxy_cache_key "$scheme://$host$uri";
            add_header X-Nginx-Cache-Head "$scheme://$host$uri";
            proxy_cache staticfilecache;
            proxy_cache_valid       200 301 302 100d;
            proxy_cache_valid 404 1m;


            add_header Cache-Control public;

            proxy_ignore_headers Expires;
            proxy_ignore_headers  "Cache-Control";
            proxy_ignore_headers X-Accel-Expires;

            proxy_hide_header "Cache-Control";
            proxy_hide_header Pragma;
            proxy_hide_header Server;
            proxy_hide_header Request-Context;
            proxy_hide_header X-Powered-By;
            proxy_cache_revalidate on;

            proxy_hide_header X-AspNet-Version;
            proxy_hide_header X-AspNetMvc-Version;
            #proxy_pass_header X-Accel-Expires;


            add_header X-Nginx-Cache-Status $upstream_cache_status;

            proxy_cache_use_stale  error timeout invalid_header updating http_500 http_502 http_503 http_504;
            proxy_cache_bypass $arg_nocache $do_not_cache $http_8X0;
            proxy_no_cache $do_not_cache;

    }

    location ~* \.(jpg|png|gif|jpeg|css|js|mp3|wav|swf|mov|doc|pdf|xls|ppt|docx|pptx|xlsx)$ {
            proxy_cache_valid 200 120d;
            expires 364d;
            add_header Cache-Control public;
            proxy_pass http://127.0.0.1:8000;
            proxy_cache staticfilecache;
            add_header X-Nginx-Cache-Status $upstream_cache_status;
            proxy_cache_use_stale  error timeout invalid_header updating http_500 http_502 http_503 http_504;
    }

Best Answer

You may need to set the inactive parameter on proxy_cache_path to something greater than 120d (or whatever you want your max cache time to actually be). The default setting for inactive is 10 minutes. So long as the URL you're caching is accessed within the inactive parameter's time frame your cache is valid but if it's not accessed within that time frame it will fall out of cache. See Understanding the nginx proxy_cache_path directive for more information.

I believe this falls outside the typical $upstream_cache_status style debugging because cache cleanup doesn't happen within the request/response cycle. AFAIK an nginx worker process does cache clean up as a low priority task if it's not doing anything else. I'm not sure where this activity would show up in logs but it's likely only going to show up with a debug enabled build.