Skip to content

Instantly share code, notes, and snippets.

@keopx
Created August 6, 2017 11:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save keopx/edc3c97c78d6891daea36c38deb457f1 to your computer and use it in GitHub Desktop.
Save keopx/edc3c97c78d6891daea36c38deb457f1 to your computer and use it in GitHub Desktop.
{% block version -%}
vcl 4.0;
{% endblock %}
# This Varnish VCL has been adapted from the Four Kitchens VCL for Varnish 3.
# Default backend definition. Points to Apache, normally.
backend default {
{% block backend -%}
.host = "{{ varnish_default_backend_host }}";
.port = "{{ varnish_default_backend_port }}";
.first_byte_timeout = 300s;
{% endblock %}
}
# Access control list for PURGE requests.
acl purge {
{% block acl_purge -%}
"127.0.0.1";
{% endblock %}
}
# Respond to incoming requests.
sub vcl_recv {
{% block http_header -%}
# Add an X-Forwarded-For header with the client IP address.
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;
}
}
{% endblock %}
{% block method_purge -%}
# Only allow PURGE requests from IP addresses in the 'purge' ACL.
if (req.method == "PURGE") {
if (!client.ip ~ purge) {
return (synth(405, "Not allowed."));
}
return (purge);
}
{% endblock %}
{% block method_ban -%}
# Only allow BAN requests from IP addresses in the 'purge' ACL.
if (req.method == "BAN") {
# Same ACL check as above:
if (!client.ip ~ purge) {
return (synth(403, "Not allowed."));
}
# Logic for the ban, using the Cache-Tags header. For more info
# see https://github.com/geerlingguy/drupal-vm/issues/397.
if (req.http.Cache-Tags) {
ban("obj.http.Cache-Tags ~ " + req.http.Cache-Tags);
}
else {
return (synth(403, "Cache-Tags header missing."));
}
# Throw a synthetic page so the request won't go to the backend.
return (synth(200, "Ban added."));
}
{% endblock %}
{% block pass_post -%}
# Only cache GET and HEAD requests (pass through POST requests).
if (req.method != "GET" && req.method != "HEAD") {
return (pass);
}
{% endblock %}
{% block pass_admin -%}
# Pass through any administrative or AJAX-related paths.
if (req.url ~ "^/status\.php$" ||
req.url ~ "^/update\.php$" ||
req.url ~ "^/admin$" ||
req.url ~ "^/admin/.*$" ||
req.url ~ "^/flag/.*$" ||
req.url ~ "^.*/ajax/.*$" ||
req.url ~ "^.*/ahah/.*$") {
return (pass);
}
{% endblock %}
{% block cookies -%}
# Removing cookies for static content so Varnish caches these files.
if (req.url ~ "(?i)\.(pdf|asc|dat|txt|doc|xls|ppt|tgz|csv|png|gif|jpeg|jpg|ico|swf|css|js)(\?.*)?$") {
unset req.http.Cookie;
}
# Remove all cookies that Drupal doesn't need to know about. We explicitly
# list the ones that Drupal does need, the SESS and NO_CACHE. If, after
# running this code we find that either of these two cookies remains, we
# will pass as the page cannot be cached.
if (req.http.Cookie) {
# 1. Append a semi-colon to the front of the cookie string.
# 2. Remove all spaces that appear after semi-colons.
# 3. Match the cookies we want to keep, adding the space we removed
# previously back. (\1) is first matching group in the regsuball.
# 4. Remove all other cookies, identifying them by the fact that they have
# no space after the preceding semi-colon.
# 5. Remove all spaces and semi-colons from the beginning and end of the
# cookie string.
set req.http.Cookie = ";" + req.http.Cookie;
set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";");
set req.http.Cookie = regsuball(req.http.Cookie, ";(SESS[a-z0-9]+|SSESS[a-z0-9]+|NO_CACHE)=", "; \1=");
set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", "");
set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", "");
if (req.http.Cookie == "") {
# If there are no remaining cookies, remove the cookie header. If there
# aren't any cookie headers, Varnish's default behavior will be to cache
# the page.
unset req.http.Cookie;
}
else {
# If there is any cookies left (a session or NO_CACHE cookie), do not
# cache the page. Pass it on to Apache directly.
return (pass);
}
}
{% endblock %}
}
# Set a header to track a cache HITs and MISSes.
sub vcl_deliver {
{% block vcl_deliver -%}
# Remove ban-lurker friendly custom headers when delivering to client.
unset resp.http.X-Url;
unset resp.http.X-Host;
unset resp.http.Purge-Cache-Tags;
if (obj.hits > 0) {
set resp.http.X-Varnish-Cache = "HIT";
}
else {
set resp.http.X-Varnish-Cache = "MISS";
}
{% endblock %}
}
# Instruct Varnish what to do in the case of certain backend responses (beresp).
sub vcl_backend_response {
{% block vcl_backend_response -%}
# Set ban-lurker friendly custom headers.
set beresp.http.X-Url = bereq.url;
set beresp.http.X-Host = bereq.http.host;
# Cache 404s, 301s, at 500s with a short lifetime to protect the backend.
if (beresp.status == 404 || beresp.status == 301 || beresp.status == 500) {
set beresp.ttl = 10m;
}
# Enable streaming directly to backend for BigPipe responses.
if (beresp.http.Surrogate-Control ~ "BigPipe/1.0") {
set beresp.do_stream = true;
set beresp.ttl = 0s;
}
# Don't allow static files to set cookies.
# (?i) denotes case insensitive in PCRE (perl compatible regular expressions).
# This list of extensions appears twice, once here and again in vcl_recv so
# make sure you edit both and keep them equal.
if (bereq.url ~ "(?i)\.(pdf|asc|dat|txt|doc|xls|ppt|tgz|csv|png|gif|jpeg|jpg|ico|swf|css|js)(\?.*)?$") {
unset beresp.http.set-cookie;
}
# Allow items to remain in cache up to 6 hours past their cache expiration.
set beresp.grace = 6h;
{% endblock %}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment