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
I think i found the problem. I needed to change this
to
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 yourvcl_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.
varnishlog -g request
log output. This should be a logging snapshot of the exact moment when the "add to cart" logic failsBased 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
andvcl_backend_response
.That’s not a quick fix, but rather a complete overhaul.
The code like:
is dangerous in itself. While it makes sense to strip incoming
Cookie
on some page (and that can be dangerous too), the pages whereSet-Cookie
in WordPress are quite limited in number unless you have a really bad plugin.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:
Do you think this is complete or something is missing, wrong or too much?