Normalize trailing slash for directory and manage 301 redirection internally

Loading

Add the following code into VCL_RECV:


vcl 4.0;
import std;

sub vcl_recv { 

  # Normalize trailing slash for directory & manage 301 redirection internally
  if (req.http.Host !~ "^www\." || 
              (req.url !~ {"(?x)
               (?:/$)         # last character isn't a slash
               |              # or
               (?:/\?)        # query string isn't immediately preceded by a slash
               "} 
               &&
               req.url ~ {"(?x)
               (?:/[^./]+$)   # last path segment doesn't contain a . no query string
               |              # or
               (?:/[^.?]+\?)  # last path segment doesn't contain a . with a query string
               "}
              )
      ) 
    {  
        return (synth(720,"Moved Permanently"));
    }
}

Add the following code into VCL_SYNTH:


sub vcl_synth {
    
  if (resp.status == 720) {
    # We use this special error status 720 to force redirects with 301 (permanent) redirects
    # To use this, call the following from anywhere in vcl_recv: return (synth(720, "http://host/new.html"));
    set resp.http.Location = resp.reason;
    set resp.status = 301;
    
    set resp.http.Location = "http://";
    set resp.http.Host = req.http.Host;
    
    if (resp.http.Host !~ "^www\.") { 
        set resp.http.Host = "www." + resp.http.Host;
    }
    
    set resp.http.Location = resp.http.Location + resp.http.Host;

    if (req.url ~ "(?:/[^./]+$)|(?:/[^.?]+\?)") {
        # no . in last path segment before optional query string
        if (req.url !~ "/$" && req.url !~ "\?") {
            # no trailing slash and no query string
            set resp.http.Location = resp.http.Location + req.url + "/";
        } elseif (req.url ~ "[^/]\?") {
           # no trailing slash and with query string, preserve it
           set resp.http.Location = resp.http.Location + regsub(req.url, "([^?]+)\?.*", "\1") + "/" + regsub(req.url, "[^?]+(\?.*)", "\1");
        } elseif (resp.http.Host != req.http.Host) {
           # trailing slash rule met, handle missing www. scenario
           set resp.http.Location = resp.http.Location + req.url;
        }
      } elseif (resp.http.Host != req.http.Host) {
            # last path segment contains a . so handle missing www. scenario
            set resp.http.Location = resp.http.Location + req.url;
        }
        
  return (deliver);
    
  } elseif (resp.status == 721) {
    # And we use error status 721 to force redirects with a 302 (temporary) redirect
    # To use this, call the following from anywhere in vcl_recv: return (synth(720, "http://host/new.html"));
    set resp.http.Location = resp.reason;
    set resp.status = 302;
    return (deliver);
  }

  return (deliver);
}

Configure BAN in VCL 4.0

Loading

To configure PURGE add this lines into your VCL_RECV:

vcl 4.0;
import std;

sub vcl_recv {

  # Allow banning  
  if (req.method == "BAN") {
     # Same ACL check as above:
     if (!client.ip ~ purge) {
        return(synth(405, "This IP is not allowed to send BAN requests."));
     }
	 ban("req.http.host == " + req.http.host + " && req.url == " + req.url);
     # Throw a synthetic page so the request won't go to the backend.
     return(synth(200, "Ban added"));
  }

}

To test it:

$ curl -v -k -H "host: www.mydomain.com" -X BAN http://varnish_server_ip/

Very useful Varnish admin command

Loading

Top REQUEST methods
varnishtop -i ReqMethod
Top URLs that MISS the cache
varnishtop -i BereqURL
Top URLS that HIT the cache
varnishtop -i ReqURL
All URLs that HIT the cache in real time
varnishlog -g request -q 'VCL_call eq HIT' | grep reqURL
All URLs that MISS the cache in real time
varnishlog -g request -q 'VCL_call eq MISS' | grep reqURL
All URLs that MISS the cache in real time
varnishlog -i BereqURL
Look at an incoming client request of a specific URL
varnishlog -c -q "ReqUrl eq '/'"
Look at a a backend request of a specific URL
varnishlog -i -q "BereqURL eq '/'"
See requests for one specific Hostname
varnishlog -c -q "ReqHeader eq 'Host: www.mydomain.com'"
See the age of the cache objects for a specific hostname
varnishlog -c -q "ReqHeader eq 'Host: www.mydomain.com'" | grep Age
All 404
varnishlog -b -q "ObjStatus eq 404"