nginxvarnish

Why does limit_except GET { deny all; } not work for PURGE requests when using nginx_http_mirror_module?


I am trying to mirror all GET requests on my nginx server, to another web application for split testing. This works and filters all request types but GET - but - unfortunately it also sends PURGE requests onwards to the mirror. So somehow the the limit_except seems to not filter those PURGE request.

Why would that be?

Here are parts of my configuration:

From HTTP block:

split_clients "${remote_addr}AAA" $mirror_backend {
    30% web_mirror;
    *   "";
 }

From server block:

location / {
    
    gunzip on;
    include /etc/nginx/proxy_params;
    mirror /mirror;

    proxy_pass http://varnish;
  }

location = /mirror {
  internal;
    limit_except GET {
    deny  all;
  }
  if ($mirror_backend = "") {
    return 400;
  }
  
  include /etc/nginx/proxy_params;
  proxy_pass http://$mirror_backend$request_uri;
}

Example output from the mirrored server which receives PURGE requests - which it shouldn't:

10.0.0.10 mydomain.com 2023-10-25T14:51:52+02:00 "PURGE /path/here HTTP/1.1" 405 0 "-" "cache-warmer/android" - "-" - - - - 99cae641-0961-48b3-9965-bfd4a8ed3ff7 0.091 - - - - ruby

Solution

  • According to the docs,

    The method parameter can be one of the following: GET, HEAD, POST, PUT, DELETE, MKCOL, COPY, MOVE, OPTIONS, PROPFIND, PROPPATCH, LOCK, UNLOCK, or PATCH.

    As you can see, PURGE is not recognized by limit_except. A workaround is to deny it explicitly (like they do here), like so

    location = /mirror {
    
        internal;
    
        if ($request_method = PURGE) {
            return 444;
        }
    
        limit_except GET {
            deny all;
        }
    
        if ($mirror_backend = "") {
            return 400;
        }
    
        include /etc/nginx/proxy_params;
        proxy_pass http://$mirror_backend$request_uri;
    }
    

    I've used 444 but feel free to use something else you deem more appropriate.