skip to Main Content

I have written this Varnish configuration for WordPress with WooCommerce. Caching and backend works, it also works completly when logged in. The only problem i am facing is that add to cart action for not loggedin users is not working and login on my account page is not working. I look forward to your help and say thank you in advance!

vcl 4.0;

backend default {
.host = "127.0.0.1";
.port = "8000";
}

sub vcl_recv {

    # pipe on weird http methods
    if (req.method !~ "^GET|HEAD|PUT|POST|TRACE|OPTIONS|DELETE$") {
        return(pipe);
    }

    if (req.method != "GET" && req.method != "HEAD") {
        return(pass);
    }

    if (req.http.X-Requested-With == "XMLHttpRequest"){
      return (pass);
    }

 if (req.http.Authorization || req.method == "POST") {
 return (pass);
 }

 if (req.url ~ "wp-(login|admin)" || req.url ~ "preview=true") {
 return (pass);
 }

if (req.url ~ "sitemap" || req.url ~ "robots") {
 return (pass);
}

  # Do not cache AJAX requests.
    if (req.http.X-Requested-With == "XMLHttpRequest") {
        return(pass);
    }

  # Woocommerce
    if (req.url ~ "(warenkorb|mein-konto|kasse|produkt)") {
        return (pass);
    }
    
    if ( req.url ~ "?add-to-cart=" ) {
        return (pass);
    }
    
        # Unset Cookies except for WordPress admin and WooCommerce pages
    if (!(req.url ~ "(wp-login|wp-admin|warenkorb|mein-konto|wc-api*|kasse|addons|logout|lost-password|produkt)")) {
        unset req.http.cookie;
    }

 set req.http.Cookie = regsuball(req.http.Cookie, "(^|;s*)(_[_a-z]+|has_js)=[^;]*", "");

 set req.http.Cookie = regsub(req.http.Cookie, "^;s*", "");

 set req.http.Cookie = regsuball(req.http.Cookie, "__qc.=[^;]+(; )?", "");

 set req.http.Cookie = regsuball(req.http.Cookie, "wp-settings-1=[^;]+(; )?", "");

 set req.http.Cookie = regsuball(req.http.Cookie, "wp-settings-time-1=[^;]+(; )?", "");

 set req.http.Cookie = regsuball(req.http.Cookie, "wordpress_test_cookie=[^;]+(; )?", "");

 if (req.http.cookie ~ "^ *$") {
 unset req.http.cookie;
 }

 if (req.url ~ ".(css|js|png|gif|jp(e)?g|swf|ico|woff|svg|htm|html)") {
 unset req.http.cookie;
 }

 if (req.http.Cookie ~ "wordpress_" || req.http.Cookie ~ "comment_") {
 return (pass);
 }

 if (!req.http.cookie) {
 unset req.http.cookie;
 }

 if (req.http.Authorization || req.http.Cookie) {
 
 return (pass);
 }

 return (hash);
}


sub vcl_pass {
 return (fetch);
}


sub vcl_hash {
    hash_data(req.url);
    if (req.http.host) {
        hash_data(req.http.host);
    } else {
        hash_data(server.ip);
    }
    return (lookup);
}

sub vcl_backend_response {
 unset beresp.http.Server;
 unset beresp.http.X-Powered-By;

 if (bereq.url ~ "sitemap" || bereq.url ~ "robots") {
 set beresp.uncacheable = true;
 set beresp.ttl = 30s;
 return (deliver);
 }

 if (bereq.url ~ ".(css|js|png|gif|jp(e?)g)|swf|ico|woff|svg|htm|html") {
 unset beresp.http.cookie;
 set beresp.ttl = 7d;
 
 # Cache-Control and Expires
 set beresp.http.Cache-Control = "public, max-age=604800";
 set beresp.http.Expires = now + beresp.ttl;
 }

 if (bereq.url ~ "wp-(login|admin)" || bereq.url ~ "preview=true") {
 set beresp.uncacheable = true;
 set beresp.ttl = 30s;
 return (deliver);
 }

 if (!(bereq.url ~ "(wp-login|wp-admin|preview=true)")) {
 unset beresp.http.set-cookie;
 }

 if ( bereq.method == "POST" || bereq.http.Authorization ) {
 set beresp.uncacheable = true;
 set beresp.ttl = 120s;
 return (deliver);
 }

 if ( bereq.url ~ "?s=" ){
 set beresp.uncacheable = true;
 set beresp.ttl = 120s;
 return (deliver);
 }
 
 if ( beresp.status != 200 ) {
 set beresp.uncacheable = true;
 set beresp.ttl = 120s;
 return (deliver);
 }
 
 set beresp.ttl = 1d;
 # The lifetime of the cache after TTL expires
 set beresp.grace = 30s;
 
     if (bereq.url !~ "wp-admin|wp-login|produkt|warenkorb|kasse|mein-konto|/?remove_item=|/?wc-ajax=") {
        unset beresp.http.set-cookie;
    }

 return (deliver);

}

sub vcl_deliver {
        if (req.http.X-Purger) {
                set resp.http.X-Purger = req.http.X-Purger;
        }
}

sub vcl_pipe {
        return (pipe);
}

sub vcl_pass {
        return (fetch);
}

4

Answers


  1. Chosen as BEST ANSWER

    I think i found the problem. I needed to change this

     if (bereq.url !~ "wp-admin|wp-login|/?remove_item=|/?wc-ajax=") {
        unset beresp.http.set-cookie;
    }
    

    to

     if (bereq.url !~ "wp-admin|wp-login|produkt|warenkorb|kasse|mein-konto|/?add-to-cart=|/?remove_item=|/?wc-ajax=") {
        unset beresp.http.set-cookie;
    }
    

  2. First impression

    I noticed your VCL configuration diverges quite a bit from the typical VCL examples. That’s OK, but it has consequences. Especially in vcl_backend_response you’ve done some customizations that aren’t at all common.

    First of all I’d like to refer to the built-in VCL for vcl_backend_response that you can find on https://github.com/varnishcache/varnish-cache/blob/6.0/bin/varnishd/builtin.vcl#L154-L168.

    I understand that the WordPress & WooCommerce logic need to be included there, but your logic seems to lack fallback behavior for the URL paths you didn’t cache.

    I’m not 100% sure what the "add to cart" URL is, but I have a feeling its Set-Cookie header is stripped off by your vcl_backend_response logic.

    How to fix your issues

    If we want to fix the issues you’re facing, we can either fix the problem at the root, or we can treat it symptomatically.

    Since I don’t have the insight into your WooCommerce setup and how it behaves, I suggest we start with a sort of symptomatic treatment.

    • Please give me the URL of the "add to cart" logic
    • Which cookies does the this shopping cart logic rely on?
    • Are there any other endpoints that are used to view and modify the shopping cart?
    • Please include an abstract of the varnishlog -g request log output. This should be a logging snapshot of the exact moment when the "add to cart" logic fails

    If you want the varnishlog output to be more relevant, you can add a URL filter to it.

    E.g.: varnishlog -g request -q "ReqUrl ~ ?add-to-cart="

    Based on the logging output and the answers to the questions, I’ll probably be able to spot what’s wrong and provide information on how to fix it.

    Longer term solutions

    If you’re looking for a cleaner, more compact VCL, I would urge you to have a look at https://github.com/varnishcache/varnish-cache/blob/6.0/bin/varnishd/builtin.vcl#L154-L168.

    This is this built-in VCL. This VCL code is added to whatever VCL subroutine you override. It’s important to know that if you don’t issue a return statement for certain situations, the built-in VCL will take over behind the scenes.

    A lot of the logic in your VCL file mimics this behavior and is not required.

    Ultimately I suggest you only extend VCL behavior in your own VCL file for logic that is not part of the built-in VCL. The goal is to reduce the lines of code in vcl_recv and vcl_backend_response.

    That’s not a quick fix, but rather a complete overhaul.

    Login or Signup to reply.
  3. The code like:

    unset beresp.http.set-cookie;
    

    is dangerous in itself. While it makes sense to strip incoming Cookie on some page (and that can be dangerous too), the pages where Set-Cookie in WordPress are quite limited in number unless you have a really bad plugin.

    Login or Signup to reply.
  4. As a result of Mr. Feryn’s and Mr. Vershinin’s remark i have minimized the configuration a lot without losing functionality as far as I could check until now:

       vcl 4.0;
    
    backend default {
    .host = "127.0.0.1";
    .port = "8000";
    }
    
    sub vcl_recv {
    
        if (req.http.Accept-Encoding) {
          if (req.url ~ ".(jpeg|jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg|swf|flv)$") {
            unset req.http.Accept-Encoding;
          } elsif (req.http.Accept-Encoding ~ "gzip") {
            set req.http.Accept-Encoding = "gzip";
          } elsif (req.http.Accept-Encoding ~ "deflate" &&
            req.http.user-agent !~ "MSIE") {
            set req.http.Accept-Encoding = "deflate";
          } else {
            unset req.http.Accept-Encoding;
          }
        }
    
     if (req.http.Authorization || req.http.Cookie) {
     
     return (pass);
     }
    
     return (hash);
    }
    
    
    sub vcl_pass {
     return (fetch);
    }
    
    
    sub vcl_hash {
    }
    
    sub vcl_backend_response {
    
     if (beresp.http.url ~ ".(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg|swf)$") {
        set beresp.do_gzip = false;
      }
      else {
        set beresp.do_gzip = true;
        set beresp.http.X-Cache = "ZIP";
      }
    
     if (bereq.url ~ "sitemap" || bereq.url ~ "robots") {
     set beresp.uncacheable = true;
     set beresp.ttl = 30s;
     return (deliver);
     }
     
     set beresp.ttl = 1d;
    # The lifetime of the cache after TTL expires
     set beresp.grace = 30s;
    
     return (deliver);
    
    }
    
    sub vcl_deliver {
    return (deliver);
    }
    
    sub vcl_pipe {
            return (pipe);
    }
    
    sub vcl_pass {
            return (fetch);
    }
    

    Do you think this is complete or something is missing, wrong or too much?

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search