Last active
May 9, 2023 16:27
-
-
Save kevin25/3a9a13706951ee764fd7e348ddde102a to your computer and use it in GitHub Desktop.
Varnish Cache WooCommerce
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
vcl 4.1; | |
import std; | |
import cookie; | |
backend default { | |
.host = "127.0.0.1"; | |
.port = "8080"; | |
} | |
# Add hostnames, IP addresses and subnets that are allowed to purge content | |
acl purge { | |
"localhost"; | |
"127.0.0.1"; | |
"::1"; | |
} | |
sub vcl_recv { | |
# Remove empty query string parameters | |
# e.g.: www.example.com/index.html? | |
if (req.url ~ "\?$") { | |
set req.url = regsub(req.url, "\?$", ""); | |
} | |
# Remove port number from host header | |
set req.http.Host = regsub(req.http.Host, ":[0-9]+", ""); | |
# Sorts query string parameters alphabetically for cache normalization purposes | |
set req.url = std.querysort(req.url); | |
# Remove the proxy header to mitigate the httpoxy vulnerability | |
# See https://httpoxy.org/ | |
unset req.http.proxy; | |
# Add X-Forwarded-Proto header when using https | |
if (!req.http.X-Forwarded-Proto) { | |
if(std.port(server.ip) == 443 || std.port(server.ip) == 8443) { | |
set req.http.X-Forwarded-Proto = "https"; | |
} else { | |
set req.http.X-Forwarded-Proto = "http"; | |
} | |
} | |
# Purge logic to remove objects from the cache. | |
# Tailored to the Proxy Cache Purge WordPress plugin | |
# See https://wordpress.org/plugins/varnish-http-purge/ | |
if(req.method == "PURGE") { | |
if(!client.ip ~ purge) { | |
return(synth(405,"PURGE not allowed for this IP address")); | |
} | |
if (req.http.X-Purge-Method == "regex") { | |
ban("obj.http.x-url ~ " + req.url + " && obj.http.x-host == " + req.http.host); | |
return(synth(200, "Purged")); | |
} | |
ban("obj.http.x-url == " + req.url + " && obj.http.x-host == " + req.http.host); | |
return(synth(200, "Purged")); | |
} | |
# Only handle relevant HTTP request methods | |
if ( | |
req.method != "GET" && | |
req.method != "HEAD" && | |
req.method != "PUT" && | |
req.method != "POST" && | |
req.method != "PATCH" && | |
req.method != "TRACE" && | |
req.method != "OPTIONS" && | |
req.method != "DELETE" | |
) { | |
return (pipe); | |
} | |
# Remove tracking query string parameters used by analytics tools | |
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, "\?&", "?"); | |
set req.url = regsub(req.url, "\?$", ""); | |
} | |
#Google Adwords | |
set req.url = regsuball(req.url,"\?gclid=[^&]+$",""); # strips when QS = "?gclid=AAA" | |
set req.url = regsuball(req.url,"\?gclid=[^&]+&","?"); # strips when QS = "?gclid=AAA&foo=bar" | |
set req.url = regsuball(req.url,"&gclid=[^&]+",""); # strips when QS = "?foo=bar&gclid=AAA" or QS = "?foo=bar&gclid=AAA&bar=baz" | |
if (req.url ~ "\#") { | |
set req.url = regsub(req.url, "\#.*$", ""); | |
} | |
# Remove the "has_js" cookie | |
set req.http.Cookie = regsuball(req.http.Cookie, "has_js=[^;]+(; )?", ""); | |
# Remove a ";" prefix in the cookie if present | |
set req.http.Cookie = regsuball(req.http.Cookie, "^;\s*", ""); | |
# remove recent | |
set req.http.Cookie = regsuball(req.http.Cookie, "woocommerce_recently_viewed=*", "; recentviewdjunk="); | |
set req.http.Cookie = regsuball(req.http.Cookie, "woocommerce_recently_viewed=[^;]+(; )?", ""); | |
if (req.http.Cookie) { | |
cookie.parse(req.http.Cookie); | |
cookie.delete("woocommerce_recently_viewed"); | |
set req.http.Cookie = cookie.get_string(); | |
} | |
# Remove test cookie | |
# set req.http.Cookie = regsuball(req.http.Cookie, "wordpress_test_cookie=", "; wpjunk="); | |
# Remove the wp-settings-1 cookie | |
# set req.http.Cookie = regsuball(req.http.Cookie, "wp-settings-1=[^;]+(; )?", ""); | |
# Remove the wp-settings-time-1 cookie | |
# set req.http.Cookie = regsuball(req.http.Cookie, "wp-settings-time-1=[^;]+(; )?", ""); | |
# Send Surrogate-Capability headers to announce ESI support to backend | |
set req.http.Surrogate-Capability = "key=ESI/1.0"; | |
# Only cache GET and HEAD requests | |
if (req.method != "GET" && req.method != "HEAD") { | |
set req.http.X-Cacheable = "NO:REQUEST-METHOD"; | |
return(pass); | |
} | |
# Mark static files with the X-Static-File header, and remove any cookies | |
# X-Static-File is also used in vcl_backend_response to identify static files | |
if (req.url ~ "^[^?]*\.(7z|avi|bmp|bz2|css|csv|doc|docx|eot|flac|flv|gif|gz|ico|jpeg|jpg|js|less|mka|mkv|mov|mp3|mp4|mpeg|mpg|odt|ogg|ogm|opus|otf|pdf|png|ppt|pptx|rar|rtf|svg|svgz|swf|tar|tbz|tgz|ttf|txt|txz|wav|webm|webp|woff|woff2|xls|xlsx|xml|xz|zip|html)(\?.*)?$") { | |
set req.http.X-Static-File = "true"; | |
unset req.http.Cookie; | |
unset req.http.set-cookie; | |
return(hash); | |
} | |
# do not cache backend for xml-rpc | |
if (req.url ~ "xmlrpc.php"){ | |
return (pass); | |
} | |
# No caching of special URLs, logged in users and some plugins | |
if ( | |
req.http.Cookie ~ "wordpress_(?!test_)[a-zA-Z0-9_]+|wp-postpass|comment_author_[a-zA-Z0-9_]+|woocommerce_cart_hash|woocommerce_items_in_cart|wp_woocommerce_session_[a-zA-Z0-9]+|wordpress_logged_in_|comment_author" || | |
req.http.Authorization || | |
req.url ~ "add_to_cart" || | |
req.url ~ "nowprocket" || | |
req.url ~ "edd_action" || | |
req.url ~ "nocache" || | |
req.url ~ "^/addons" || | |
req.url ~ "^/bb-admin" || | |
req.url ~ "^/bb-login.php" || | |
req.url ~ "^/bb-reset-password.php" || | |
req.url ~ "^/cart" || | |
req.url ~ "^/checkout" || | |
req.url ~ "^/control.php" || | |
req.url ~ "^/login" || | |
req.url ~ "^/logout" || | |
req.url ~ "^/wp-json" || | |
req.url ~ "^/lost-password" || | |
req.url ~ "^/my-account" || | |
req.url ~ "^/product" || | |
req.url ~ "^/register" || | |
req.url ~ "^/register.php" || | |
req.url ~ "^/server-status" || | |
req.url ~ "^/signin" || | |
req.url ~ "^/signup" || | |
req.url ~ "^/stats" || | |
req.url ~ "^/wc-api" || | |
req.url ~ "^/wp-admin" || | |
req.url ~ "^/wcpa_uploads" || | |
req.url ~ "^/uploads" || | |
req.url ~ "^/wp-comments-post.php" || | |
req.url ~ "^/wp-cron.php" || | |
req.url ~ "^/wp-login.php" || | |
req.url ~ "^/wp-activate.php" || | |
req.url ~ "^/wp-mail.php" || | |
req.url ~ "^/wp-login.php" || | |
req.url ~ "^\?add-to-cart=" || | |
req.url ~ "^\?wc-api=" || | |
req.url ~ "^/preview=" || | |
req.url ~ "^/\.well-known/acme-challenge/" | |
#req.url ~ "nowprocket" | |
) { | |
set req.http.X-Cacheable = "NO:Logged in/Got Sessions"; | |
if(req.http.X-Requested-With == "XMLHttpRequest") { | |
set req.http.X-Cacheable = "NO:Ajax"; | |
} | |
return(pass); | |
} | |
#set req.http.Cookie = regsuball(req.http.Cookie, "woocommerce_recently_viewed=[^;]+(; )?", ""); | |
# remove Are there cookies left with only spaces or that are empty? | |
# if (req.http.cookie ~ "^\s*$") { | |
# unset req.http.cookie; | |
# return(hash); | |
# } | |
if (req.http.Cookie ~ "^\s*$") { | |
unset req.http.cookie; | |
} | |
return (hash); | |
#return(hash); | |
# remove recent view | |
#set req.http.Cookie = regsuball(req.http.Cookie, "woocommerce_recently_viewed", ""); | |
# Remove any cookies left | |
# unset req.http.Cookie; | |
# return(hash); | |
# if (req.http.Cookie ~ "^\s*$") { | |
# unset req.http.cookie; | |
# return(hash); | |
# } | |
} | |
sub vcl_hash { | |
if(req.http.X-Forwarded-Proto) { | |
# Create cache variations depending on the request protocol | |
hash_data(req.http.X-Forwarded-Proto); | |
} | |
} | |
sub vcl_backend_response { | |
# Inject URL & Host header into the object for asynchronous banning purposes | |
set beresp.http.x-url = bereq.url; | |
set beresp.http.x-host = bereq.http.host; | |
#if ( beresp.http.Content-Type ~ "image" ) | |
# { | |
# set beresp.ttl = 2h; ## 1 hour TTL for images | |
# } | |
# If we dont get a Cache-Control header from the backend | |
# we default to 1h cache for all objects | |
if (!beresp.http.Cache-Control) { | |
set beresp.ttl = 24h; | |
set beresp.http.X-Cacheable = "YES:Forced"; | |
} | |
# If the file is marked as static we cache it for 1 day | |
if (bereq.http.X-Static-File == "true") { | |
unset beresp.http.Set-Cookie; | |
set beresp.http.X-Cacheable = "YES:Forced"; | |
set beresp.ttl = 1d; | |
} | |
# Remove the Set-Cookie header when a specific Wordfence cookie is set | |
if (beresp.http.Set-Cookie ~ "woocommerce_recently_viewed") { | |
unset beresp.http.Set-Cookie; | |
} | |
if (beresp.http.Set-Cookie) { | |
set beresp.http.X-Cacheable = "NO:Got Cookies"; | |
} elseif(beresp.http.Cache-Control ~ "private") { | |
set beresp.http.X-Cacheable = "NO:Cache-Control=private"; | |
} | |
# Cache all static files by Removing all cookies for static files - Note: These file extensions are generated by WordPress WP Super Cache. | |
if (bereq.url ~ "^[^?]*\.(html|htm|gz)(\?.*)?$") { | |
set beresp.ttl = 1d; # set a TTL for these optional. | |
unset beresp.http.set-cookie; | |
} | |
return (deliver); | |
} | |
sub vcl_deliver { | |
# Debug header | |
if(req.http.X-Cacheable) { | |
set resp.http.X-Cacheable = req.http.X-Cacheable; | |
} elseif(obj.uncacheable) { | |
if(!resp.http.X-Cacheable) { | |
set resp.http.X-Cacheable = "NO:UNCACHEABLE"; | |
} | |
} elseif(!resp.http.X-Cacheable) { | |
set resp.http.X-Cacheable = "YES"; | |
} | |
if (obj.hits > 0) { ## Add the X-Cache: HIT/MISS/BYPASS header | |
set resp.http.X-Cache = "HIT"; ## If we had a HIT | |
} else { | |
set resp.http.X-Cache = "MISS"; ## If we had a MISS | |
} | |
# Cleanup of headers | |
unset resp.http.x-url; | |
unset resp.http.x-host; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment