Create a gist now

Instantly share code, notes, and snippets.

Embed
Varnish 4 VCL configuration for WordPress. Also allows purging
# A heavily customized VCL to support WordPress
# Some items of note:
# Supports https
# Supports admin cookies for wp-admin
# Caches everything
# Support for custom error html page
vcl 4.0;
import directors;
import std;
# Assumed 'wordpress' host, this can be docker servicename
backend default {
.host = "wordpress";
.port = "80";
}
acl purge {
"localhost";
"127.0.0.1";
}
sub vcl_recv {
# Only a single backend
set req.backend_hint= default;
# Setting http headers for backend
set req.http.X-Forwarded-For = client.ip;
set req.http.X-Forwarded-Proto = "https";
# Unset headers that might cause us to cache duplicate infos
unset req.http.Accept-Language;
unset req.http.User-Agent;
# The purge...no idea if this works
if (req.method == "PURGE") {
if (!client.ip ~ purge) {
return(synth(405,"Not allowed."));
}
return (purge);
}
if ( std.port(server.ip) == 6080) {
set req.http.x-redir = "https://" + req.http.host + req.url;
return (synth(750, "Moved permanently"));
}
# drop cookies and params from static assets
if (req.url ~ "\.(gif|jpg|jpeg|swf|ttf|css|js|flv|mp3|mp4|pdf|ico|png)(\?.*|)$") {
unset req.http.cookie;
set req.url = regsub(req.url, "\?.*$", "");
}
# drop tracking params
if (req.url ~ "\?(utm_(campaign|medium|source|term)|adParams|client|cx|eid|fbid|feed|ref(id|src)?|v(er|iew))=") {
set req.url = regsub(req.url, "\?.*$", "");
}
# pass wp-admin urls
if (req.url ~ "(wp-login|wp-admin)" || req.url ~ "preview=true" || req.url ~ "xmlrpc.php") {
return (pass);
}
# pass wp-admin cookies
if (req.http.cookie) {
if (req.http.cookie ~ "(wordpress_|wp-settings-)") {
return(pass);
} else {
unset req.http.cookie;
}
}
}
sub vcl_backend_response {
# retry a few times if backend is down
if (beresp.status == 503 && bereq.retries < 3 ) {
return(retry);
}
if (bereq.http.Cookie ~ "(UserID|_session)") {
# if we get a session cookie...caching is a no-go
set beresp.http.X-Cacheable = "NO:Got Session";
set beresp.uncacheable = true;
return (deliver);
} elsif (beresp.ttl <= 0s) {
# Varnish determined the object was not cacheable
set beresp.http.X-Cacheable = "NO:Not Cacheable";
} elsif (beresp.http.set-cookie) {
# You don't wish to cache content for logged in users
set beresp.http.X-Cacheable = "NO:Set-Cookie";
set beresp.uncacheable = true;
return (deliver);
} elsif (beresp.http.Cache-Control ~ "private") {
# You are respecting the Cache-Control=private header from the backend
set beresp.http.X-Cacheable = "NO:Cache-Control=private";
set beresp.uncacheable = true;
return (deliver);
} else {
# Varnish determined the object was cacheable
set beresp.http.X-Cacheable = "YES";
# Remove Expires from backend, it's not long enough
unset beresp.http.expires;
# Set the clients TTL on this object
set beresp.http.cache-control = "max-age=900";
# Set how long Varnish will keep it
set beresp.ttl = 1w;
# marker for vcl_deliver to reset Age:
set beresp.http.magicmarker = "1";
}
# unset cookies from backendresponse
if (!(bereq.url ~ "(wp-login|wp-admin)")) {
set beresp.http.X-UnsetCookies = "TRUE";
unset beresp.http.set-cookie;
set beresp.ttl = 1h;
}
# long ttl for assets
if (bereq.url ~ "\.(gif|jpg|jpeg|swf|ttf|css|js|flv|mp3|mp4|pdf|ico|png)(\?.*|)$") {
set beresp.ttl = 365d;
}
set beresp.grace = 1w;
}
sub vcl_hash {
if ( req.http.X-Forwarded-Proto ) {
hash_data( req.http.X-Forwarded-Proto );
}
}
sub vcl_backend_error {
# display custom error page if backend down
if (beresp.status == 503 && bereq.retries == 3) {
synthetic(std.fileread("/etc/varnish/error503.html"));
return(deliver);
}
}
sub vcl_synth {
# redirect for http
if (resp.status == 750) {
set resp.status = 301;
set resp.http.Location = req.http.x-redir;
return(deliver);
}
# display custom error page if backend down
if (resp.status == 503) {
synthetic(std.fileread("/etc/varnish/error503.html"));
return(deliver);
}
}
sub vcl_deliver {
# oh noes backend is down
if (resp.status == 503) {
return(restart);
}
if (resp.http.magicmarker) {
# Remove the magic marker
unset resp.http.magicmarker;
# By definition we have a fresh object
set resp.http.age = "0";
}
if (obj.hits > 0) {
set resp.http.X-Cache = "HIT";
} else {
set resp.http.X-Cache = "MISS";
}
set resp.http.Access-Control-Allow-Origin = "*";
}
sub vcl_hit {
if (req.method == "PURGE") {
return(synth(200,"OK"));
}
}
sub vcl_miss {
if (req.method == "PURGE") {
return(synth(404,"Not cached"));
}
}
@makmour

This comment has been minimized.

Show comment
Hide comment
@makmour

makmour Feb 28, 2016

Hi!
There is something worng with

 if ( (!(bereq.url ~ "(wp-(login|admin)|login)")) || (bereq.method == "GET") ) {
        unset beresp.http.set-cookie;
        set beresp.ttl = 1s;
        }

because it makes WP to fail loading the test cookie thus not permitting users to login into the Dashboard,

makmour commented Feb 28, 2016

Hi!
There is something worng with

 if ( (!(bereq.url ~ "(wp-(login|admin)|login)")) || (bereq.method == "GET") ) {
        unset beresp.http.set-cookie;
        set beresp.ttl = 1s;
        }

because it makes WP to fail loading the test cookie thus not permitting users to login into the Dashboard,

@matthewjackowski

This comment has been minimized.

Show comment
Hide comment
@matthewjackowski

matthewjackowski Mar 14, 2016

@makmour I reduced the logic on that condition and also set an X-param to be able to see when it triggers. Seems to be ok for me on my local docker setup. Keep in mind that to enable https you have todo alot of tomfoolery in Wordpress too.

Owner

matthewjackowski commented Mar 14, 2016

@makmour I reduced the logic on that condition and also set an X-param to be able to see when it triggers. Seems to be ok for me on my local docker setup. Keep in mind that to enable https you have todo alot of tomfoolery in Wordpress too.

@oralunal

This comment has been minimized.

Show comment
Hide comment
@oralunal

oralunal Dec 29, 2016

It works great, thank you sir

It works great, thank you sir

@marco41

This comment has been minimized.

Show comment
Hide comment
@marco41

marco41 Jul 14, 2017

Hi, it works great with https. But not all my sites are https. I can not log in to my sites with http. How do I add a code for this to help you?

marco41 commented Jul 14, 2017

Hi, it works great with https. But not all my sites are https. I can not log in to my sites with http. How do I add a code for this to help you?

@danhere

This comment has been minimized.

Show comment
Hide comment
@danhere

danhere Sep 4, 2017

Thanks for this! There's a surprising lack of good/up to date configs out there.

I did run into small issue though: Have you noticed that Wordpress' Visual Editor doesn't load with this config? I disabled Varnish all together and the Visual Editor comes right back. I can't seem to figure it out. Any ideas?

danhere commented Sep 4, 2017

Thanks for this! There's a surprising lack of good/up to date configs out there.

I did run into small issue though: Have you noticed that Wordpress' Visual Editor doesn't load with this config? I disabled Varnish all together and the Visual Editor comes right back. I can't seem to figure it out. Any ideas?

@marco41

This comment has been minimized.

Show comment
Hide comment
@marco41

marco41 Sep 24, 2017

Hello,
Normally : http://prntscr.com/gp860w
But it looks like this. : http://prntscr.com/gp85ws

How can my overcome this problem?

marco41 commented Sep 24, 2017

Hello,
Normally : http://prntscr.com/gp860w
But it looks like this. : http://prntscr.com/gp85ws

How can my overcome this problem?

@dockrize

This comment has been minimized.

Show comment
Hide comment
@dockrize

dockrize Sep 25, 2017

@marco41 @danhere
Check the HTTP requests at your browser (developer console). I saw this problem when doing HTTP requests to a HTTPS port.

@marco41 @danhere
Check the HTTP requests at your browser (developer console). I saw this problem when doing HTTP requests to a HTTPS port.

@marco41

This comment has been minimized.

Show comment
Hide comment
@marco41

marco41 Sep 28, 2017

@dockrize what should I do. Please tell me in detail.

marco41 commented Sep 28, 2017

@dockrize what should I do. Please tell me in detail.

@marco41

This comment has been minimized.

Show comment
Hide comment
@marco41

marco41 Oct 8, 2017

@matthewjackowski If you know, please answer me?

marco41 commented Oct 8, 2017

@matthewjackowski If you know, please answer me?

@informdev

This comment has been minimized.

Show comment
Hide comment
@informdev

informdev Dec 13, 2017

So far this is excellent. I keep reading about issues people have ran into with CloudFlare and Varnish -- I'm still new to this stuff but so far it SEEMS to be working? Any thoughts, ideas? fixes if an issue?

So far this is excellent. I keep reading about issues people have ran into with CloudFlare and Varnish -- I'm still new to this stuff but so far it SEEMS to be working? Any thoughts, ideas? fixes if an issue?

@informdev

This comment has been minimized.

Show comment
Hide comment
@informdev

informdev Dec 13, 2017

To everyone else @Marco31 @danhere -- you can fix your editor issues by bypassing caching if logged in.
Under sub vcl_recv { add the following:
if (req.url ~ "wp-(login|admin|comments-post.php|cron.php)" ||
req.url ~ "preview=true" ||
req.url ~ "xmlrpc.php") {
return (pass);
}

informdev commented Dec 13, 2017

To everyone else @Marco31 @danhere -- you can fix your editor issues by bypassing caching if logged in.
Under sub vcl_recv { add the following:
if (req.url ~ "wp-(login|admin|comments-post.php|cron.php)" ||
req.url ~ "preview=true" ||
req.url ~ "xmlrpc.php") {
return (pass);
}

@marco41

This comment has been minimized.

Show comment
Hide comment
@marco41

marco41 Jan 8, 2018

@informdev thank you so much. My problem is resolved.

marco41 commented Jan 8, 2018

@informdev thank you so much. My problem is resolved.

@hazhayder

This comment has been minimized.

Show comment
Hide comment
@hazhayder

hazhayder Mar 23, 2018

It shows apache default page when i ran this vcl file.

It shows apache default page when i ran this vcl file.

@xoroz

This comment has been minimized.

Show comment
Hide comment
@xoroz

xoroz Apr 12, 2018

Tried all configurations I still have the same problem as Marco41...
TinyMCE does not work once varnish is activated. Without it, it works!

Please someone help us out.

I noticed without varnish these URLs

http://felipeferreira.net/wp-content/themes/bandana/css/editor-style.css?wp-mce-4607-20180123-tadv-4.6.7
http://felipeferreira.net/wp-includes/js/tinymce/plugins/compat3x/plugin.min.js?ver=4607-20180123-tadv-4.6.7
http://felipeferreira.net/wp-includes/js/tinymce/tinymce.min.js?ver=4607-20180123-tadv-4.6.7
http://felipeferreira.net/wp-includes/js/tinymce/skins/wordpress/wp-content.css?ver=4.9.5&wp-mce-4607-20180123-tadv-4.6.7

Then with varnish ON, I no longer see those, and I see something trunked like:
http://felipeferreira.net/wp-includes/js/mce-view.min.js?ver=4.9.5

have been struginling with this problem for over 2 years now, I have tried
if (req.url ~ "wp-(login|admin|comments-post.php|cron.php)" ||
req.url ~ "preview=true" ||
req.url ~ "xmlrpc.php") {
return (pass);
}
if (req.url ~ "(tinymce|wp-mce|plugin.min.js)" ||
req.url ~ "preview=true" ||
req.url ~ "xmlrpc.php") {
return (pass);
}

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

but did not work...

xoroz commented Apr 12, 2018

Tried all configurations I still have the same problem as Marco41...
TinyMCE does not work once varnish is activated. Without it, it works!

Please someone help us out.

I noticed without varnish these URLs

http://felipeferreira.net/wp-content/themes/bandana/css/editor-style.css?wp-mce-4607-20180123-tadv-4.6.7
http://felipeferreira.net/wp-includes/js/tinymce/plugins/compat3x/plugin.min.js?ver=4607-20180123-tadv-4.6.7
http://felipeferreira.net/wp-includes/js/tinymce/tinymce.min.js?ver=4607-20180123-tadv-4.6.7
http://felipeferreira.net/wp-includes/js/tinymce/skins/wordpress/wp-content.css?ver=4.9.5&wp-mce-4607-20180123-tadv-4.6.7

Then with varnish ON, I no longer see those, and I see something trunked like:
http://felipeferreira.net/wp-includes/js/mce-view.min.js?ver=4.9.5

have been struginling with this problem for over 2 years now, I have tried
if (req.url ~ "wp-(login|admin|comments-post.php|cron.php)" ||
req.url ~ "preview=true" ||
req.url ~ "xmlrpc.php") {
return (pass);
}
if (req.url ~ "(tinymce|wp-mce|plugin.min.js)" ||
req.url ~ "preview=true" ||
req.url ~ "xmlrpc.php") {
return (pass);
}

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

but did not work...

@arpan-jain

This comment has been minimized.

Show comment
Hide comment
@arpan-jain

arpan-jain May 4, 2018

Hey, @xoroz, I had the same problem with the WordPress visual editor, But adding the code snippet as the very first condition to evaluated in vcl_recv fixed it for me.

Pasting the same code snippet here for reference.

# Added later to fix visual editor issues
  if (req.url ~ "wp-(login|admin|comments-post.php|cron.php)" || req.url ~ "preview=true" || req.url ~ "xmlrpc.php") {
             return (pass);
   }

Hope it helps.

arpan-jain commented May 4, 2018

Hey, @xoroz, I had the same problem with the WordPress visual editor, But adding the code snippet as the very first condition to evaluated in vcl_recv fixed it for me.

Pasting the same code snippet here for reference.

# Added later to fix visual editor issues
  if (req.url ~ "wp-(login|admin|comments-post.php|cron.php)" || req.url ~ "preview=true" || req.url ~ "xmlrpc.php") {
             return (pass);
   }

Hope it helps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment