Jump to content

Varnish 4 VCL for Prestashop 1.6


moy2010

Recommended Posts

Hi, Prestashop Community Members. I've been recently playing with Varnish 4 as an attempt to reduce my Prestashop 1.6 site's loading time. So far so good, the loading time have now decreased to ~1.5s and decided to share my VCL with the community so that we can create a big-single VCL configuration file for Varnish 4  for performance, security and a high hit-rate with the feedback from the whole community.

 

Varnish 4 VCL for Prestashop v0.2 (Updated on May 06th, 2016):

 

#
# This is an example VCL file for Varnish.
#
# It does not do anything by default, delegating control to the
# builtin VCL. The builtin VCL is called when there is no explicit
# return statement.
#
# See the VCL chapters in the Users Guide at https://www.varnish-cache.org/docs/
 
# Marker to tell the VCL compiler that this VCL has been adapted to the
# new 4.0 format.
vcl 4.0;
 
# Default backend definition. Set this to point to your content server.
backend default {
    .host = "127.0.0.1";
    .port = "8080";
}
 
sub vcl_recv {
  # Only deal with "normal" types
  if (req.method != "GET" &&
      req.method != "HEAD" &&
      req.method != "PUT" &&
      req.method != "POST" &&
      req.method != "TRACE" &&
      req.method != "OPTIONS" &&
      req.method != "PATCH" &&
      req.method != "DELETE") {
    /* Non-RFC2616 or CONNECT which is weird. */
    return (pass);
  }
  # Only cache GET or HEAD requests. This makes sure the POST requests are always passed.
  if (req.method != "GET" && req.method != "HEAD") {
    return (pass);
  }
 # Some generic URL manipulation, useful for all templates that follow
  # First remove the Google Analytics added parameters, useless for our backend
  if (req.url ~ "(\?|&)(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=") {
    set req.url = regsuball(req.url, "&(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "");
    set req.url = regsuball(req.url, "\?(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "?");
    set req.url = regsub(req.url, "\?$", "");
  }
 
  # Strip a trailing ? if it exists
  if (req.url ~ "\?$") {
    set req.url = regsub(req.url, "\?$", "");
  }
 
  # Strip hash, server doesn't need it.
  if (req.url ~ "\#") {
    set req.url = regsub(req.url, "\#.*$", "");
  }
 
if (req.http.Accept-Encoding) {
    # Do no compress compressed files...
    if (req.url ~ "\.(jpg|png|gif|woff2|gz|tgz|bz2|tbz)$") {
          unset req.http.Accept-Encoding;
    } elsif (req.http.Accept-Encoding ~ "gzip") {
          set req.http.Accept-Encoding = "gzip";
    } elsif (req.http.Accept-Encoding ~ "deflate") {
          set req.http.Accept-Encoding = "deflate";
    } else {
      unset req.http.Accept-Encoding;
    }
  }
# Remove the "has_js" cookie
  set req.http.Cookie = regsuball(req.http.Cookie, "has_js=[^;]+(; )?", "");
 
  # Remove any Google Analytics based cookies
  set req.http.Cookie = regsuball(req.http.Cookie, "__utm.=[^;]+(; )?", "");
  set req.http.Cookie = regsuball(req.http.Cookie, "_ga=[^;]+(; )?", "");
  set req.http.Cookie = regsuball(req.http.Cookie, "_gat=[^;]+(; )?", "");
  set req.http.Cookie = regsuball(req.http.Cookie, "utmctr=[^;]+(; )?", "");
  set req.http.Cookie = regsuball(req.http.Cookie, "utmcmd.=[^;]+(; )?", "");
  set req.http.Cookie = regsuball(req.http.Cookie, "utmccn.=[^;]+(; )?", "");
 
  # Remove DoubleClick offensive cookies
  set req.http.Cookie = regsuball(req.http.Cookie, "__gads=[^;]+(; )?", "");
 
  # Remove the Quant Capital cookies (added by some plugin, all __qca)
  set req.http.Cookie = regsuball(req.http.Cookie, "__qc.=[^;]+(; )?", "");
 
  # Remove the AddThis cookies
  set req.http.Cookie = regsuball(req.http.Cookie, "__atuv.=[^;]+(; )?", "");
 
  # Remove a ";" prefix in the cookie if present
  set req.http.Cookie = regsuball(req.http.Cookie, "^;\s*", "");
 
  # Are there cookies left with only spaces or that are empty?
  if (req.http.cookie ~ "^\s*$") {
    unset req.http.cookie;
}
 
#we should not cache any page for sales
if (req.method == "GET" && (req.url ~ "^/cart.php" || req.url ~ "^/order.php")) {
    return (pass);
}
#we should not cache any page for sales
if (req.method == "GET" && (req.url ~ "^/addresses.php" || req.url ~ "^/order-detail.php")) {
    return (pass);
}
#we should not cache any page for sales
if (req.method == "GET" && (req.url ~ "^/order-confirmation.php" || req.url ~ "^/order-return.php")) {
    return (pass);
}
if (req.url ~ "^[^?]*\.(css|js|jpg|png|gif|woff|woff2)(\?.*)?$") {
    unset req.http.Cookie;
  }
if (req.http.Authorization || req.http.Authenticate)
{
  return (pass);
}
}
 
sub vcl_backend_response {
# Avoid Header Expires in the past
if (beresp.ttl > 0s && (bereq.method == "GET" || bereq.method == "HEAD")) {
    unset beresp.http.set-cookie;
    unset beresp.http.Expires;
    set beresp.ttl = 24h;
    unset beresp.http.Cache-Control;
    # Set new Cache-Control headers for browsers to store cache for 7 days
    set beresp.http.Cache-Control = "public, max-age=604800";
    set beresp.http.magicmarker = "1";
    set beresp.http.cachable = "1";
        if (bereq.url !~ "\.(css|js|jpg|png|gif|woff|woff2|html|htm|gz)(\?|$)") {
            set beresp.http.Pragma = "no-cache";
            set beresp.http.Expires = "-1";
            set beresp.http.Cache-Control = "no-store, no-cache, must-revalidate, max-age=0";
            set beresp.grace = 1m;
        }
        return(deliver);
        }
  # Sometimes, a 301 or 302 redirect formed via Apache's mod_rewrite can mess with the HTTP port that is being passed along.
  # This often happens with simple rewrite rules in a scenario where Varnish runs on :80 and Apache on :8080 on the same box.
  # A redirect can then often redirect the end-user to a URL on :8080, where it should be :80.
  # This may need finetuning on your setup.
  #
  # To prevent accidental replace, we only filter the 301/302 redirects for now.
  if (beresp.status == 301 || beresp.status == 302) {
    set beresp.http.Location = regsub(beresp.http.Location, ":[0-9]+", "");
  }
 
  # Don't cache 50x responses
  if (beresp.status == 500 || beresp.status == 502 || beresp.status == 503 || beresp.status == 504) {
    return (abandon);
  }
 
  # Allow stale content, in case the backend goes down.
  # make Varnish keep all objects for 1 hour beyond their TTL
  set beresp.grace = 1h;
 
  return (deliver);
}
 
sub vcl_deliver {
if(obj.hits > 0) {
     set resp.http.X-Cache = "HIT";
  } else {
    set resp.http.X-Cache = "MISS";
  }
  # Remove some headers: PHP version
  unset resp.http.X-Powered-By;
  # Remove some headers: Apache version & OS
  unset resp.http.Server;
  # Remove some heanders: Varnish
  unset resp.http.Via;
  unset resp.http.X-Varnish;
}
Edited by moy2010 (see edit history)
  • Like 5
Link to comment
Share on other sites

  • 2 weeks later...

Thanks for sharing! I am using it on my server, but I am only getting MISS-es, I don't know why, can you help please?

Accept-Ranges:bytes
Age:0
Connection:keep-alive
Content-Encoding:gzip
Content-Type:text/html; charset=utf-8
Date:Sun, 15 May 2016 22:51:01 GMT
P3P:CP="IDC DSP COR CURa ADMa OUR IND PHY ONL COM STA"
Server:nginx
Transfer-Encoding:chunked
Vary:Accept-Encoding
Via:1.1 varnish-v4
X-Cache:MISS
X-Varnish:262170
Link to comment
Share on other sites

Check if you are performing the tests while logged in. Varnish doesn't handle cookies, and the VCL I shared completely misses the varnish cache for logged users.

I am not logged in, not in front, not in admin. I tried browsing in "incognito" mode and still only MISS. Cleared all the history in the browser and only MISS.

Link to comment
Share on other sites

  • 4 weeks later...

Hello,

 

thanks for sharing you VCL ! I've a problem between varnish and Google pagespeed tool.

 

With your configuration I can access to my website. Any idea ?

 

For more speed on Prestashop, it would be interested to focus on 3 points : varnish, pagespeed and htaccess !

 

thx for answer 

Link to comment
Share on other sites

  • 2 months later...

Thank you very much for sharing this configuration, it works like a charm !

However, with this configuration, the very first request is always a miss, is it normal ?


For example, when I try to load the home page, the "/" request is always a miss and the very first request of a category page or a CMS page is always a miss.

Although, all the other resources are fine and properly cached.
 

I think it is due to the presence of the HTML code containing the cart and the amount of the cart, am I right ?

Thank you very much for your help

Edited by flo62134 (see edit history)
Link to comment
Share on other sites

Hi, flo62134. Indeed there are multiple explanations for a miss with varnish cache as you said.

 

Varnish cache works with objects and it's based on urls, so that if you call the same object from multiple urls you will have duplicated objects in your cache.

 

In my case, I had to normalize all my urls prior to achieving a high hitrate in varnish. A common example is to redirect all www.yoursite.com traffic to yoursite.com or the other way around. If your varnish sits behind your web server, you'll have to make the redirections on varnish, otherwise it may always have a miss on the first request.

 

In conclusion:

Check the first request in terms of objects and urls. If you find what's different between the requested and the cached object you'll find what the problem is.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...