I have just set up a server with just varnish installed in front of my backend server, where I have two different django sites, being served through nginx+gunicorn
It seem to work, but I get Header Age = 0, and looking at the documentation, that's not very good.
I want to cache pages for anonymous users, but not for authenticated users or if a user have a cookie called "AUTHENTICATION"
Here is my default.vcl
backend django {
.host = "backend1";
.port = "8080";
}
sub vcl_recv {
# unless sessionid/csrftoken is in the request, don't pass ANY cookies (referral_source, utm, etc)
if (req.request == "GET" && (req.url ~ "^/static" || (req.http.cookie !~ "sessionid" && req.http.cookie !~ "csrftoken" && req.http.cookie !~ "AUTHENTICATION"))) {
remove req.http.Cookie;
}
#normalize accept-encoding to account for different browsers
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 {
# unknown algorithm
remove req.http.Accept-Encoding;
}
}
}
sub vcl_fetch {
# /static and /media files always cached
if (req.url ~ "^/static" || req.url ~ "^/media") {
unset beresp.http.set-cookie;
return (deliver);
}
# pass through for anything with a session/csrftoken set
if (beresp.http.set-cookie ~ "sessionid" || beresp.http.set-cookie ~ "csrftoken" || beresp.http.set-cookie ~ "AUTHENTICATION") {
return (hit_for_pass);
} else {
return (deliver);
}
}
Could it be that sessionid
is set for every user, even if they are not logged in, and that is preventing Varnish effectively cache pages for anon users?
Using isvarnishworking.com this is the output:
HTTP/1.1 200 OK
Server: cloudflare-nginx
Date: Fri, 15 Nov 2013 09:30:20 GMT
Content-Type: text/html; charset=utf-8
Connection: keep-alive
Set-Cookie: __cfduid=d281023a84b2e5351d109c1848eeca1601384507820317; expires=Mon, 23-Dec-2019 23:50:00 GMT; path=/; domain=.mydomain.com; HttpOnly
Vary: Cookie
X-Frame-Options: SAMEORIGIN
X-Varnish: 1602772074
Age: 0
Via: 1.1 varnish
CF-RAY: cdaec14fab00412
Content-Encoding: gzip
My new default.vcl:
backend django {
.host = "backend1";
.port = "8080";
}
sub vcl_recv {
#normalize accept-encoding to account for different browsers
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 {
# unknown algorithm
remove req.http.Accept-Encoding;
}
}
}
sub vcl_fetch {
if (req.url ~ "^/static" || req.url ~ "^/media") {
unset beresp.http.set-cookie;
}
if (beresp.http.set-cookie !~ "sessionid" && beresp.http.set-cookie !~ "csrftoken" && beresp.http.set-cookie !~ "AUTHENTICATION") {
unset beresp.http.set-cookie;
}
}
Result from isvarnishworking.com
HTTP/1.1 200 OK
Server: cloudflare-nginx
Date: Fri, 15 Nov 2013 12:08:42 GMT
Content-Type: text/html; charset=utf-8
Connection: keep-alive
Set-Cookie: __cfduid=d55ea1b56e978cbbf3384d0fa2f21571e1384517322491; expires=Mon, 23-Dec-2019 23:50:00 GMT; path=/; domain=.mydomain.com; HttpOnly
Vary: Cookie
X-Frame-Options: SAMEORIGIN
X-Varnish: 1240916568
Age: 0
Via: 1.1 varnish
CF-RAY: cdbd4119f3b0412
Content-Encoding: gzip
backend default {
.host = "backend1";
.port = "8080";
}
sub vcl_recv {
# unless sessionid/csrftoken is in the request, don't pass ANY cookies (referral_source, utm, etc)
if (req.request == "GET" && (req.url ~ "^/static" || (req.http.cookie !~ "sessionid" && req.http.cookie !~ "csrftoken" && req.http.cookie !~ "AUTHENTICATION"))) {
remove req.http.Cookie;
}
#normalize accept-encoding to account for different browsers
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 {
# unknown algorithm
remove req.http.Accept-Encoding;
}
}
}
sub vcl_fetch {
# /static and /media files always cached
if (req.url ~ "^/static" || req.url ~ "^/media") {
unset beresp.http.set-cookie;
}
if (beresp.http.set-cookie !~ "sessionid" && beresp.http.set-cookie !~ "csrftoken" && beresp.http.set-cookie !~ "AUTHENTICATION") {
unset beresp.http.set-cookie;
}
}
My backend response (without varnish in front) is:
GET / HTTP/1.1
Host: www.mydomain.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:25.0) Gecko/20100101 Firefox/25.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: nb-no,nb;q=0.9,no-no;q=0.8,no;q=0.6,nn-no;q=0.5,nn;q=0.4,en-us;q=0.3,en;q=0.1
Accept-Encoding: gzip, deflate
Cookie: __cfduid=d8f496aef561efd7a30c3d9f909a02cf31384507505064; sessionid=twoq45r21gn341545ohubilyp739r42ee; _ga=GA1.2.382479980.1384507508
Connection: keep-alive
HTTP/1.1 200 OK
Server: cloudflare-nginx
Date: Fri, 15 Nov 2013 14:37:53 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Language, Cookie
X-Frame-Options: SAMEORIGIN
Content-Language: nb
CF-RAY: cdcae94f68105af
Content-Encoding: gzip
Varnish is tremendously fast and relies on pthreads to handle a massive amount of incoming requests. The threading model and the use of memory for storage will result in a significant performance boost of your application. If configured correctly, Varnish Cache can easily make your website 1,000 times faster.
To verify that Varnish is proxying look for the existence of the X-Varnish header in the response. The Age header will be 0 on a cache miss and above zero on a hit. The first request to a page will always be a miss.
Could it be that sessionid is set for every user, even if they are not logged in, and that is preventing Varnish effectively cache pages for anon users?
You are correct. After logout a new session is immediately started and a new session cookie is planted on user's machine. To work around this problem I created a custom logout view that I use with sites I use with Varnish:
from django.conf import settings
from django.contrib.auth.views import logout
def logout_user(request):
"""After logging out some of the cookies should be deleted,
allowing upstream cache to work effectively."""
response = logout(request)
request.session.modified = False # forces session middleware not to set its own cookie
response.delete_cookie(settings.CSRF_COOKIE_NAME)
response.delete_cookie(settings.SESSION_COOKIE_NAME)
return response
As you can see I force session middleware not to set a new cookie, and then I delete the old cookies (I also get rid of the csrf cookie).
Edit: Also, this code seems completely unnecessary, as Varnish do this automatically for any cookie being set:
# pass through for anything with a session/csrftoken set
if (beresp.http.set-cookie ~ "sessionid" || beresp.http.set-cookie ~ "csrftoken" || beresp.http.set-cookie ~ "AUTHENTICATION") {
return (hit_for_pass);
} else {
return (deliver);
}
Also note that hit_for_pass
will make a particular URL not cachable for a couple of minutes (for all users!). Try those three diagnostics:
Age
is still set to 0
.Age
value itself, or forcing Varnish to do so using other cache control cookies?varlog
to check if those responses are being cached.Edit 2: Your isvarnishworking.com output shows that the servers sets a cookie called __cfduid
. Every time cookie is set Varnish automatically enters hit-for-pass mode (see the code I linked to in the edit above). That is most likely the reason of the problem. I guess that was the reason for the code I deemed unnecessary. I'd try explicitly removing all unknown cookies:
sub vcl_fetch {
if (req.url ~ "^/static" || req.url ~ "^/media") {
unset beresp.http.set-cookie;
}
if (beresp.http.set-cookie !~ "sessionid" && beresp.http.set-cookie !~ "csrftoken" && beresp.http.set-cookie !~ "AUTHENTICATION") {
unset beresp.http.set-cookie;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With