How to make Varnish Place Nice with WPtouch Pro

I have a WordPress site that uses WPTouch Pro for Mobile. I have a nginx server with varnish cache. The problem is I can’t get Varnish WPTouch Pro and WordPress to work nice together. There are a lot of solutions on the Web, but nothing has worked. The attached default.vcl is the closest I’ve been able to come. Varnish appears to be caching for both desktop an mobile sites and both display properly. But now WordPress doesn’t work properly. I can’t save posts, can’t show preview pages and difficulty logging in. Varnish appears to be caching the admin pages. I know there is a simple solution. Please help me find it. Here’s the vcl

# Set the default backend (Nginx server for me)
backend default {
    .host = "127.0.0.1";
    .port = "8080";
        .connect_timeout = 600s;
        .first_byte_timeout = 1200s;
        .between_bytes_timeout = 600s;
        .max_connections = 2800;
}

# Purge ACL
acl purge {
        "localhost";
}

# This function is used when a request is send by a HTTP client (Browser) 
# !!! Replace: blog.nicolargo.com by your own URL !!!

sub vcl_recv {
set req.grace = 10m;

  call detect_device;

   # Set X-Forwarded-For header for logging in nginx
  remove req.http.X-Forwarded-For;
  set    req.http.X-Forwarded-For = client.ip;


  # Allow purging from ACL
  if (req.request == "PURGE") {
    # If not allowed then a error 405 is returned
    if (!client.ip ~ purge) {
      error 405 "This IP is not allowed to send PURGE requests.";
    } 
    # If allowed, do a cache_lookup -> vlc_hit() or vlc_miss()
    return (lookup);
  }

  # Post requests will not be cached
  if (req.request == "POST") {
    return (pass);
  }

  # --- WordPress specific configuration

  # Did not cache the RSS feed
  if (req.url ~ "/feed") {
      return (pass);
  }

  # Did not cache the admin and login pages
  if (req.url ~ "/wp-(login|admin)") {
    return (pass);
  }

  // server1 must handle file uploads
  if (req.url ~ "media-upload.php" || req.url ~ "file.php" || req.url ~ "async-upload.php") {
    return(pass);
  }

  // do not cache xmlrpc.php
  if (req.url ~ "xmlrpc.php") {
    return(pass);
  }

  // strip cookies from xmlrpc
  if (req.request == "GET" && req.url ~ "xmlrpc.php"){
      remove req.http.cookie;return(pass);
  }

  # 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.=[^;]+(; )?", "");

  # Remove the Quant Capital cookies (added by some plugin, all __qca)
  set req.http.Cookie = regsuball(req.http.Cookie, "__qc.=[^;]+(; )?", "");

  # 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=[^;]+(; )?", "");

  # Are there cookies left with only spaces or that are empty?
  if (req.http.cookie ~ "^ *$") {
        unset req.http.cookie;
  }

  if (req.http.Accept-Encoding) {
    # Do no compress compressed files...
    if (req.url ~ ".(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg)$") {
          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 {
      remove req.http.Accept-Encoding;
    }
  }

  # Cache the following files extensions 
  if (req.url ~ ".(css|js|png|gif|jp(e)?g)") {
    unset req.http.cookie;
  }

  # Check the cookies for wordpress-specific items
  if (req.http.Cookie ~ "wordpress_" || req.http.Cookie ~ "comment_") {
    return (pass);
  }
  if (!req.http.cookie) {
    unset req.http.cookie;
  }

  # --- End of WordPress specific configuration

  # Did not cache HTTP authentication and HTTP Cookie
  if (req.http.Authorization || req.http.Cookie) {
    # Not cacheable by default
    return (pass);
  }

  # Cache all others requests
  return (lookup);
}

 sub vcl_pipe {
  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);
  }

  # ensure separate cache for mobile clients (WPTouch workaround)
  if (req.http.X-Device ~ "smart" || req.http.X-Device ~ "other") {
    hash_data(req.http.X-Device);
  } 

  # 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 detect_device {
  # Define the desktop device and ipad
  set req.http.X-Device = "desktop";

  if (req.http.User-Agent ~ "iP(hone|od)" || req.http.User-Agent ~ "Android" ) {
    # Define smartphones and tablets
    set req.http.X-Device = "smart";
  }

  elseif (req.http.User-Agent ~ "SymbianOS" || req.http.User-Agent ~ "^BlackBerry" || req.http.User-Agent ~ "^SonyEricsson" || req.http.User-Agent ~ "^Nokia" || req.http.User-Agent ~ "^SAMSUNG" || req.http.User-Agent ~ "^LG") {
    # Define every other mobile device
    set req.http.X-Device = "other";
  }

# Try a cache-lookup
return (lookup);

}

sub vcl_fetch {
        #set obj.grace = 5m;
    set beresp.grace = 2m;

}

sub vcl_hit {
        if (req.request == "PURGE") {
                purge;
                error 200 "Purged.";
        }
}

sub vcl_miss {
        if (req.request == "PURGE") {
                purge;
                error 200 "Purged.";
        }
}
# Drop any cookies sent to WordPress.
sub vcl_recv {
    if (!(req.url ~ "wp-(login|admin)")) {
        unset req.http.cookie;
    }
}

# Drop any cookies WordPress tries to send back to the client.
sub vcl_fetch {
    if (!(req.url ~ "wp-(login|admin)")) {
        unset beresp.http.set-cookie;
    }
}

Related posts

1 comment

  1. You need to pass content containing the wordpress logged in cookie.

    In your sub vcl_recv

    # OPTIONAL: DO NOT CACHE LOGGED IN USERS (THIS OCCURS IN FETCH TOO, EITHER
      # COMMENT OR UNCOMMENT BOTH
      # ##########################################################
      if ( req.http.cookie ~ "wordpress_logged_in" ) {
        return( pass );
      }
    

    Full working vcl for WordPress to use hash_always_miss is here which you may find userful

Comments are closed.