# VCL configuration file for Varnish | |
# Define which IP addresses or hosts have access to files that are | |
# blocked from the public internet | |
acl internal { | |
"localhost"; | |
} | |
# Define origin servers | |
backend web { .host = "1.2.3.4"; .port = "80"; } | |
backend web_ssl { .host = "1.2.3.4"; .port = "443"; } | |
# Uncomment to support Munin graphs | |
# backend monitoring { .host = "127.0.0.1"; .port = "8081"; } | |
# Uncomment to include Security.VCL module | |
# @see: https://github.com/comotion/security.vcl | |
# include "/etc/varnish/security/main.vcl"; | |
# Respond to incoming requests | |
sub vcl_recv { | |
# Uncomment to support Munin graphs. Access is granted if visitor is coming | |
# from a whitelisted IP address and secret token is provided. | |
# e.g. http://www.example.com/munin?your-secret-token | |
# if (req.url ~ "^/munin" && client.ip ~ internal | |
# && (req.url ~ "\?your-secret-token" | |
# || req.http.referer ~ "(www\.)?example\.com")) { | |
# set req.backend = monitoring; | |
# return (pipe); | |
# } | |
# Uncomment to have New Relic track queue times | |
# C{ | |
# #include </etc/varnish/newrelic.h> | |
# }C | |
# Handle HTTPS connection | |
if (server.port == 443) { | |
set req.backend = web_ssl; | |
} else { | |
set req.backend = web; | |
} | |
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 requests sent via curls -X mode and LWP | |
if (req.url ~ "^http://") { | |
set req.url = regsub(req.url, "http://[^/]*", ""); | |
} | |
# Normalize hostname to avoid double caching | |
set req.http.host = regsub(req.http.host, | |
"^example\.com$", "www.example.com"); | |
# Uncomment to support shared hosting when testing through staging server | |
# set req.http.host = regsub(req.http.host, "^cache\.example\.com$", | |
# "www.example.com"); | |
# Use anonymous, cached pages if all backends are down | |
if (!req.backend.healthy) { | |
unset req.http.Cookie; | |
} | |
# Allow the backend to serve up stale content if it is responding slowly | |
set req.grace = 6h; | |
# Do not cache these paths | |
if (req.url ~ "^/status\.php$" || | |
req.url ~ "^/administrator") { | |
return (pass); | |
} | |
# Do not cache authenticated sessions | |
if (req.http.Cookie && req.http.Cookie ~ "authtoken=") { | |
return (pipe); | |
} | |
# Do not allow outside access to configuration.php | |
if (req.url ~ "^/configuration\.php$" && !client.ip ~ internal) { | |
# Have Varnish throw the error directly | |
# error 404 "Page not found."; | |
# Use a custom error page | |
set req.url = "/"; | |
} | |
# Allow purge only from internal users | |
if (req.request == "PURGE") { | |
if (!client.ip ~ internal) { | |
error 405 "Not allowed."; | |
} | |
return (lookup); | |
} | |
# Handle compression correctly. Different browsers send different | |
# "Accept-Encoding" headers, even though they mostly all support the same | |
# compression mechanisms. By consolidating these compression headers into | |
# a consistent format, we can reduce the size of the cache and get more hits. | |
# @see: http:// varnish.projects.linpro.no/wiki/FAQ/Compression | |
if (req.http.Accept-Encoding) { | |
if (req.http.Accept-Encoding ~ "gzip") { | |
# If the browser supports it, we'll use gzip. | |
set req.http.Accept-Encoding = "gzip"; | |
} else if (req.http.Accept-Encoding ~ "deflate") { | |
# Next, try deflate if it is supported. | |
set req.http.Accept-Encoding = "deflate"; | |
} else { | |
# Unknown algorithm. Remove it and send unencoded. | |
unset req.http.Accept-Encoding; | |
} | |
} | |
# Always cache the following file types for all users | |
if (req.url ~ | |
"(?i)\.(png|gif|jpeg|jpg|ico|swf|pdf|txt|css|js|html|htm|gz|xml)(\?[a-z0-9]+)?$") { | |
unset req.http.Cookie; | |
} | |
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") { | |
return (pass); | |
} | |
# We cache requests with cookies too (e.g. Google Analytics) | |
# Original: if (req.http.Authenticate || req.http.Authorization | |
# || req.http.Cookie) { | |
if (req.http.Authenticate || req.http.Authorization) { | |
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. | |
# return (pipe); | |
# } | |
# sub vcl_pass { | |
# return (pass); | |
# } | |
# Determine the cache key when storing/retrieving a cached page | |
sub vcl_hash { | |
hash_data(req.url); | |
if (req.http.host) { | |
hash_data(req.http.host); | |
} else { | |
hash_data(server.ip); | |
} | |
# Don't include cookie in hash | |
# if (req.http.Cookie) { | |
# hash_data(req.http.Cookie); | |
# } | |
return (hash); | |
} | |
sub vcl_hit { | |
if (req.request == "PURGE") { | |
purge; | |
error 200 "Purged."; | |
} | |
if (obj.ttl <= 0s) { | |
return (pass); | |
} | |
return (deliver); | |
} | |
sub vcl_miss { | |
if (req.request == "PURGE") { | |
error 404 "Not in cache."; | |
} | |
return (fetch); | |
} | |
# Called when the requested object has been retrieved from the backend, or the | |
# request to the backend has failed; "beresp" stands for back-end response | |
sub vcl_fetch { | |
# Don't allow static files to set cookies | |
if (req.url ~ | |
"(?i)\.(png|gif|jpeg|jpg|ico|swf|pdf|txt|css|js|html|htm|gz|xml)(\?[a-z0-9]+)?$") { | |
unset beresp.http.Set-cookie; | |
} | |
# Allow items to be stale if needed | |
set beresp.grace = 6h; | |
if (beresp.ttl <= 0s) { | |
set beresp.http.X-Cacheable = "NO:Not Cacheable"; | |
return (hit_for_pass); | |
} else if (req.http.Cookie ~"(UserID|_session)") { | |
# Don't cache content for logged in users | |
set beresp.http.X-Cacheable = "NO:Got Session"; | |
return (hit_for_pass); | |
} else if (beresp.http.Cache-Control ~ "private") { | |
# Respect the Cache-Control=private header from the backend | |
set beresp.http.X-Cacheable = "NO:Cache-Control=private"; | |
return (hit_for_pass); | |
} else if (beresp.ttl < 1s) { | |
# Extend the lifetime of the object artificially | |
set beresp.ttl = 300s; | |
set beresp.grace = 300s; | |
set beresp.http.X-Cacheable = "YES:Forced"; | |
} else { | |
# Varnish determined the object was cacheable | |
set beresp.http.X-Cacheable = "YES"; | |
# Uncomment to have Varnish cache objects longer than the clients do. | |
# Cache must be purged manually when the site changes, so don't use with | |
# frequently changing content - comments, visitor counters etc. | |
# @see: https://www.varnish-cache.org/trac/wiki/VCLExampleLongerCaching | |
# unset beresp.http.expires; | |
# set beresp.ttl = 1w; | |
# set beresp.http.magicmarker = "1"; | |
} | |
return (deliver); | |
} | |
sub vcl_deliver { | |
# Uncomment to add hostname to headers | |
# set resp.http.X-Served-By = server.hostname; | |
# Identify which Varnish handled the request | |
if (obj.hits > 0) { | |
set resp.http.X-Cache = "HIT from Tokyo"; | |
set resp.http.X-Cache-Hits = obj.hits; | |
} else { | |
set resp.http.X-Cache = "MISS from Tokyo"; | |
} | |
# Remove version number sometimes set by CMS | |
if (resp.http.X-Content-Encoded-By) { | |
unset resp.http.X-Content-Encoded-By; | |
} | |
if (resp.http.magicmarker) { | |
# Remove the magic marker, see vcl_fetch | |
unset resp.http.magicmarker; | |
# By definition we have a fresh object | |
set resp.http.Age = "0"; | |
} | |
return (deliver); | |
} | |
sub vcl_error { | |
# Redirect to some other URL in case of root page failure | |
# if (req.url ~ "^/?$") { | |
# set obj.status = 302; | |
# set obj.http.Location = "http://backup.example.com/"; | |
# } | |
# Otherwise redirect to root, which will likely be in the cache | |
set obj.http.Content-Type = "text/html; charset=utf-8"; | |
synthetic {" | |
<html> | |
<head> | |
<title>Page Unavailable</title> | |
<style> | |
body { background: #efefef; text-align: center; color: white; | |
font-family: Trebuchet MS, sans-serif; } | |
#page { width: 500px; margin: 100px auto 0; padding: 30px; background: #888888; | |
border-radius: 14px; -moz-border-radius: 14px; -webkit-border-radius: 14px; border: 0 } | |
a, a:link, a:visited { color: #cccccc; } | |
.error { color: #222222; } | |
</style> | |
</head> | |
<body onload="setTimeout(function() { window.location = '/' }, 3000)"> | |
<div id="page"> | |
<h1 class="title">Page Unavailable</h1> | |
<p>The page you requested is temporarily unavailable.</p> | |
<p>We're redirecting you to the <a href="/">homepage</a> in 3 seconds.</p> | |
<div class="error">(Error "} + obj.status + " " + obj.response + {")</div> | |
</div> | |
</body> | |
</html> | |
"}; | |
return (deliver); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment