Skip to content

Instantly share code, notes, and snippets.

@amorken
Created June 26, 2012 21:20
Show Gist options
  • Save amorken/2999141 to your computer and use it in GitHub Desktop.
Save amorken/2999141 to your computer and use it in GitHub Desktop.
VCL file for Wordpress @ tjomlid.com
# Default backend definition. Set this to point to your content
# server.
backend default {
# I have Virtual Hosts that only listen to the Public IP
# so no 127.0.0.1 for me
# Backend is running on port 80
.host = "82.116.79.20";
.port = "80";
.first_byte_timeout = 300s;
}
acl purge {
# For now, I'll only allow purges coming from localhost
"127.0.0.1";
"localhost";
}
# Handle the HTTP request received by the client
sub vcl_recv {
if (req.restarts == 0) {
if (req.http.X-Forwarded-For) {
set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip;
} else {
set req.http.X-Forwarded-For = client.ip;
}
}
# Normalize the header, remove the port (in case you're testing this on various TCP ports)
set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");
# Allow purging
if (req.request == "PURGE") {
if (!client.ip ~ purge) {
# Not from an allowed IP? Then die with an error.
error 405 "This IP is not allowed to send PURGE requests.";
}
# If you got this stage (and didn't error out above), do a cache-lookup
# That will force entry into vcl_hit() or vcl_miss() below and purge the actual cache
return (lookup);
}
# Only deal with "normal" types
if (req.request != "GET" &&
req.request != "HEAD" &&
req.request != "PUT" &&
req.request != "POST" &&
req.request != "TRACE" &&
req.request != "OPTIONS" &&
req.request != "DELETE") {
/* Non-RFC2616 or CONNECT which is weird. */
return (pipe);
}
if (req.request != "GET" && req.request != "HEAD") {
# We only deal with GET and HEAD by default
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|gclid|cx|ie|cof|siteurl)=") {
set req.url = regsuball(req.url, "&(utm_source|utm_medium|utm_campaign|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "");
set req.url = regsuball(req.url, "\?(utm_source|utm_medium|utm_campaign|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "?");
set req.url = regsub(req.url, "\?&", "?");
set req.url = regsub(req.url, "\?$", "");
}
# Strip hash, server doesn't need it.
if (req.url ~ "\#") {
set req.url = regsub(req.url, "\#.*$", "");
}
# Strip a trailing ? if it exists
if (req.url ~ "\?$") {
set req.url = regsub(req.url, "\?$", "");
}
# Some generic cookie manipulation, useful for all templates that follow
# 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, "utmctr=[^;]+(; )?", "");
set req.http.Cookie = regsuball(req.http.Cookie, "utmcmd.=[^;]+(; )?", "");
set req.http.Cookie = regsuball(req.http.Cookie, "utmccn.=[^;]+(; )?", "");
# Remove the Quant Capital cookies (added by some plugin, all __qca)
set req.http.Cookie = regsuball(req.http.Cookie, "__qc.=[^;]+(; )?", "");
# Are there cookies left with only spaces or that are empty?
if (req.http.cookie ~ "^ *$") {
unset req.http.cookie;
}
# Normalize Accept-Encoding header
# straight from the manual: https://www.varnish-cache.org/docs/3.0/tutorial/vary.html
if (req.http.Accept-Encoding) {
if (req.url ~ "\.(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg)$") {
# No point in compressing these
remove 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 {
# unkown algorithm
remove req.http.Accept-Encoding;
}
}
# Include the correct Virtual Host configuration file
if (req.http.Host == "tjomlid.com") {
# Redirect the user if it's not on the "real" domain name (a 301 permanent redirect, SEO)
if (req.http.Host != "tjomlid.com") {
error 701 "tjomlid.com";
}
# Either the admin pages or the login, or a preview
if (req.url ~ "(/wp-(login|admin)|preview=true)") {
# Don't cache, pass to backend
return (pass);
}
# 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=[^;]+(; )?", "");
# Remove the wp test cookie
set req.http.Cookie = regsuball(req.http.Cookie, "wordpress_test_cookie=[^;]+(; )?", "");
# Static content unique to the theme can be cached (so no user uploaded images)
# The reason I don't take the wp-content/uploads is because of cache size on bigger blogs
# that would fill up with all those files getting pushed into cache
if (req.url ~ "wp-content/themes/" && req.url ~ "\.(css|js|png|gif|jp(e)?g)") {
unset req.http.cookie;
}
# Even if no cookies are present, I don't want my "uploads" to be cached due to their potential size
if (req.url ~ "/wp-content/uploads/") {
return (pass);
}
# Check the cookies for wordpress-specific items
if (req.http.Cookie ~ "wordpress_" || req.http.Cookie ~ "comment_") {
# A wordpress specific cookie has been set
return (pass);
}
# Anything else left?
if (!req.http.cookie) {
unset req.http.cookie;
}
# Try a cache-lookup
return (lookup);
} else {
# Something not specified? Pass, I probably don't want it cached.
return (pass);
}
if (req.http.Authorization || req.http.Cookie) {
# Not cacheable by default
return (pass);
}
return (lookup);
}
sub vcl_pipe {
# Note that only the first request to the backend will have
# X-Forwarded-For set. If you use X-Forwarded-For and want to
# have it set for all requests, make sure to have:
# set bereq.http.connection = "close";
# here. It is not set by default as it might break some broken web
# applications, like IIS with NTLM authentication.
set bereq.http.Connection = "Close";
return (pipe);
}
sub vcl_pass {
return (pass);
}
# The data on which the hashing will take place
sub vcl_hash {
hash_data(req.url);
if (req.http.host) {
hash_data(req.http.host);
} else {
hash_data(server.ip);
}
# If the client supports compression, keep that in a different cache
if (req.http.Accept-Encoding) {
hash_data(req.http.Accept-Encoding);
}
return (hash);
}
sub vcl_hit {
# Allow purges
if (req.request == "PURGE") {
purge;
error 200 "Purged.";
}
return (deliver);
}
sub vcl_miss {
# Allow purges
if (req.request == "PURGE") {
purge;
error 200 "URL Purged.";
}
return (fetch);
}
# Handle the HTTP request coming from our backend
sub vcl_fetch {
# I can use direct matching on the host, since I normalized the host header in the VCL Receive
if (req.http.Host == "tjomlid.com") {
# For static content related to the theme, strip all backend cookies
if (req.url ~ "wp-content/themes/" && req.url ~ "\.(css|js|png|gif|jp(e?)g)") {
unset beresp.http.cookie;
}
# A TTL of 30 minutes
set beresp.ttl = 1800s;
}
# Temporarily removed
#if (beresp.ttl <= 0s || beresp.http.Set-Cookie || beresp.http.Vary == "*") {
# set beresp.ttl = 120s;
# return (hit_for_pass);
#}
return (deliver);
}
# The routine when we deliver the HTTP request to the user
# Last chance to modify headers that are sent to the client
sub vcl_deliver {
if (obj.hits > 0) {
set resp.http.X-Cache = "cached";
} else {
set resp.http.x-Cache = "uncached";
}
# Remove some headers: PHP version
unset resp.http.X-Powered-By;
# Remove some headers: Apache version & OS
unset resp.http.Server;
return (deliver);
}
sub vcl_error {
if (obj.status == 701) {
# Redirect error handler
set obj.http.Location = "http://" + obj.response + req.url;
# Change this to 302 if you want temporary redirects
set obj.status = 301;
return (deliver);
}
return (deliver);
}
sub vcl_init {
return (ok);
}
sub vcl_fini {
return (ok);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment