3. Varnish Cache

Check if Varnish 4+ is available on your box directly from the debian/ubuntu repositories… If not, you’ll have to grab and install it ‘by hand’, from

a) checking for availability locally:
  • sudo apt-get update
    sudo apt-cache policy varnish
  • if you get something like this:
    • apt-cache policy varnish
       Installed: 4.1.1-1
       Candidate: 4.1.1-1
       Version table:
       *** 4.1.1-1 500
       500 xenial/universe amd64 Packages
       100 /var/lib/dpkg/status
  • then you can simply install it like this:
    • sudo apt-get install varnish
b) grab and install ‘manually’:
  • wget
  • tar xvzf varnish-4.1.6.tar.gz
  • cd varnish-4.1.6
  • ./configure
  • ./make
  • ./make install

This assumes that you have all the development software dependencies satisfied on that box, if not, look up how that’s done. Typically, by installing more stuff via ‘apt-get install’, but this stuff is well outside the scope of this how-to.

Time to configure Varnish. And here’s the deal. By default, after installation, it’ll be occupying and listening ports 6081 (and can be managed internally on port 6082).

That’s fine. We can easily modify the default port to the desired 80 by yet again breaking out your Vim skills and editing the file at: /etc/default/varnish, and going from:

START=no to START=yes


DAEMON_OPTS="-a :6081 \
 -T localhost:6082 \
 -f /etc/varnish/default.vcl \
 -S /etc/varnish/secret \
 -s malloc,256m"


DAEMON_OPTS="-a :80 \
 -T localhost:6082 \
 -f /etc/varnish/custom.vcl \
 -S /etc/varnish/secret \
 -s malloc,512m"


Then there’s also another file at /lib/systemd/system/varnish.service which needs a changin’ from:

ExecStart=/usr/sbin/varnishd -j unix,user=vcache -F -a :6081 -T localhost:6082 -f /etc/varnish/default.vcl -S /etc/varnish/secret -s malloc,256m


ExecStart=/usr/sbin/varnishd -j unix,user=vcache -F -a :80 -T localhost:6082 -f /etc/varnish/custom.vcl -S /etc/varnish/secret -s malloc,512m


Last bit is to actually make a nice /etc/varnish/custom.vcl configuration file for your newly minted varnish installation, in which we tell it what to cache, what not to cache, how to handle each type of request, and so on:

sudo vi /etc/varnish/custom.vcl

and paste this bit in, modifying it accordingly with your domain name:

vcl 4.0;
backend default {
 .host = "localhost";
 .port = "8080";
 .probe = {
 .url = "/";
 .interval = 60s;
 .timeout = 5s;
 .window = 5;
 .threshold = 3;
acl purger {

sub vcl_recv {
 if (client.ip != "" && ~ "<your-domain>.com") {
 set req.http.x-redir = "https://<your-domain>.com" + req.url;
 return(synth(850, ""));
 if (req.method == "PURGE") {
 if (!client.ip ~ purger) {
 return(synth(405, "This IP is not allowed to send PURGE requests."));
 return (purge);
 if (req.http.Authorization || req.method == "POST") {
 return (pass);
 if (req.url ~ "wp-admin|wp-login") {
 return (pass);


sub vcl_synth {
 if (resp.status == 850) {
 set resp.http.Location = req.http.x-redir;
 set resp.status = 302;
 return (deliver);

sub vcl_backend_response {
 set beresp.ttl = 24h;
 set beresp.grace = 1h;
 if (bereq.url !~ "wp-admin|wp-login|product|cart|checkout|my-account|/?remove_item=") {
 unset beresp.http.set-cookie;

sub vcl_deliver {
 if (req.http.X-Purger) {
 set resp.http.X-Purger = req.http.X-Purger;
 unset resp.http.Server;
 set resp.http.Via = "Varnish";
 set resp.http.Server = "<some string to identify your server, typically Nginx or Apache>";
 set resp.http.X-Powered-By = "Wordpress";
 if (resp.http.X-Varnish ~ "[0-9]+ +[0-9]+") {
 set resp.http.X-Cache = "HIT";
 unset resp.http.X-Varnish;
 } else {
 set resp.http.X-Cache = "MISS";
 unset resp.http.X-Varnish;

Write a Comment


  1. HTTP/1.1 403 Forbidden
    Server: nginx/1.10.3 (Ubuntu)
    Date: Sat, 29 Sep 2018 17:23:22 GMT
    Content-Type: text/html; charset=utf-8
    Connection: keep-alive
    Expires: Wed, 11 Jan 1984 05:00:00 GMT
    Cache-Control: no-cache, must-revalidate, max-age=0

    i get this response

    • would you mind posting both your NGINX configuration as well as your Varnish configuration? Also, please be specific as to your OS flavor and version.

  2. 1. Your tutorial works for me. But after I logged in with admin account, access any url with “/wp-admin/*”, results a 302 (see below). Any ideas? – – [13/Dec/2018:15:48:34 +0000] “GET /home/wp-admin/post-new.php HTTP/1.1” 302 0 “” “Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36”

    2. In some tutorial, they added the following configs. Do we need them?

    define( ‘WP_HOME’, ‘https://your-site’ );
    define( ‘WP_SITEURL’, ‘https://your-site’ );
    define(‘FORCE_SSL_ADMIN’, true);
    define(‘FORCE_SSL_LOGIN’, true);