varnish-vs-nginx-fastcgi-cache-768x373

About Varnish

Varnish is a HTTP accelerator; in other words a caching server. It allows us to speed up websites by directing HTTP requests static copy of the website maintained and produced by Varnish.

About Nginx

Nginx is a lightweight, high performance HTTP server that will serve as the backend service to Varnish. It will not directly serve websites to visitors; however, it will respond to requests from Varnish whenever cache is required to be built.

How do Nginx and Varnish work?
nginx-varnish

Install nginx, varnish

yum install varnish
yum install nginx

Config nginx listen on port 8081

server {
        listen 8081;
        server_name www.example.com;
        rewrite ^(.*) http://example.com$1 permanent;
        }
server {
        listen 8081 default_server;
        server_name example.com;
        ....................

}

Varnish

  • Stop nginx and varnish
  • Config varnish vi /etc/varnish/default.vcl (for wordpress)
#
# This is an example VCL file for Varnish.
#
# It does not do anything by default, delegating control to the
# builtin VCL. The builtin VCL is called when there is no explicit
# return statement.
#
# See the VCL chapters in the Users Guide at https://www.varnish-cache.org/docs/
# and http://varnish-cache.org/trac/wiki/VCLExamples for more examples.

# Update for work with Varnish 4


# Marker to tell the VCL compiler that this VCL has been adapted to the
# new 4.0 format.
vcl 4.0;

# Default backend definition. Set this to point to your content server.
backend default {
    .host = "127.0.0.1";
    .port = "8081";
    .connect_timeout = 600s;
    .first_byte_timeout = 600s;
    .between_bytes_timeout = 600s;
    .max_connections = 800;
}

# Only allow purging from specific IPs
acl purge {
    "localhost";
    "127.0.0.1";
}

# This function is used when a request is send by a HTTP client (Browser)
sub vcl_recv {
        # Normalize the header, remove the port (in case you're testing this on various TCP ports)
        set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");

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

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

        # --- WordPress specific configuration

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

        # Blitz hack
        if (req.url ~ "/mu-.*") {
                return (pass);
        }


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

        # Unset Cookies except for WordPress admin and WooCommerce pages
        if (!(req.url ~ "(wp-login|wp-admin|wc-ajax|cart|my-account/*|checkout|addons|logout|lost-password|product/*)")) {
                unset req.http.cookie;
        }
        # Pass through the WooCommerce dynamic pages
        if (req.url ~ "^/(cart|my-account/*|checkout|wc-ajax|addons|logout|lost-password|product/*)") {
                return (pass);
        }
        # Pass through the WooCommerce add to cart
        if (req.url ~ "\?add-to-cart=" ) {
                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;
        }

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

        # Normalize Accept-Encoding header and compression
        # https://www.varnish-cache.org/docs/3.0/tutorial/vary.html
        if (req.http.Accept-Encoding) {
                # Do no compress compressed files...
                if (req.url ~ "\.(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg)$") {
                                unset 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 {
                        unset req.http.Accept-Encoding;
                }
        }
        # 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 (hash);
}

sub vcl_pipe {
        return (pipe);
}

sub vcl_pass {
        return (fetch);
}

# 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);
        }

        # If the client supports compression, keep that in a different cache
        if (req.http.Accept-Encoding) {
                hash_data(req.http.Accept-Encoding);
        }

        return (lookup);
}

# This function is used when a request is sent by our backend (Nginx server)
sub vcl_backend_response {
        # Remove some headers we never want to see
        unset beresp.http.Server;
        unset beresp.http.X-Powered-By;

        # For static content strip all backend cookies
        if (bereq.url ~ "\.(css|js|png|gif|jp(e?)g)|swf|ico") {
                unset beresp.http.cookie;
        }

        # Only allow cookies to be set if we're in admin area
        #if (beresp.http.Set-Cookie && bereq.url !~ "/wp-(login|admin)") {
        #       unset beresp.http.Set-Cookie;
        #}

        #Only allow cookies to be set if we're in admin area and WooCommerce pages
        # Unset Cookies except for WordPress admin and WooCommerce pages
        if ( (!(bereq.url ~ "(wp-login|wp-admin|login|cart|my-account/*|checkout|addons|logout|lost-password|product/*)")) || (bereq.method == "GET") ) {
                unset beresp.http.Set-Cookie;
        }


        # don't cache response to posted requests or those with basic auth
        if ( bereq.method == "POST" || bereq.http.Authorization ) {
                set beresp.uncacheable = true;
                set beresp.ttl = 120s;
                return (deliver);
        }

        # don't cache search results
        if ( bereq.url ~ "\?s=" ){
                set beresp.uncacheable = true;
                set beresp.ttl = 120s;
                return (deliver);
        }

        # only cache status ok
        if ( beresp.status != 200 ) {
                set beresp.uncacheable = true;
                set beresp.ttl = 120s;
                return (deliver);
        }

        # A TTL of 24h
        set beresp.ttl = 24h;
        # Define the default grace period to serve cached content
        set beresp.grace = 30s;

        return (deliver);
}

# The routine when we deliver the HTTP request to the user
# Last chance to modify headers that are sent to the client
sub vcl_deliver {
        if (obj.hits > 0) {
                set resp.http.X-Cache = "Hit";
        } else {
                set resp.http.x-Cache = "Miss";
        }

        # Remove some headers: PHP version
        unset resp.http.X-Powered-By;

        # Remove some headers: Apache version & OS
        unset resp.http.Server;

        # Remove some heanders: Varnish
        unset resp.http.Via;
        unset resp.http.X-Varnish;

        return (deliver);
}

sub vcl_init {
        return (ok);
}

sub vcl_fini {
        return (ok);
}


  • Config varnish vi /etc/varnish/varnish.params
# Varnish environment configuration description. This was derived from
# the old style sysconfig/defaults settings
# Set this to 1 to make systemd reload try to switch vcl without restart.
RELOAD_VCL=1

# Main configuration file. You probably want to change it.
VARNISH_VCL_CONF=/etc/varnish/default.vcl

# Default address and port to bind to. Blank address means all IPv4
# and IPv6 interfaces, otherwise specify a host name, an IPv4 dotted
# quad, or an IPv6 address in brackets.
VARNISH_LISTEN_ADDRESS=
VARNISH_LISTEN_PORT=80

# Admin interface listen address and port
VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1
VARNISH_ADMIN_LISTEN_PORT=6082

# Shared secret file for admin interface
VARNISH_SECRET_FILE=/etc/varnish/secret

# Backend storage specification, see Storage Types in the varnishd(5)
# man page for details.
VARNISH_STORAGE="file,/var/lib/varnish/varnish_storage.bin,1G"

# Default TTL used when the backend does not specify one
VARNISH_TTL=120

# User and group for the varnishd worker processes
VARNISH_USER=varnish
VARNISH_GROUP=varnish

# Other options, see the man page varnishd(1)
#DAEMON_OPTS="-a :80 -p thread_pool_min=5 -p thread_pool_max=500 -p thread_pool_timeout=300"
DAEMON_OPTS="-a :80 \
             -T localhost:6082 \
             -f /etc/varnish/default.vcl \
             -S /etc/varnish/secret \
             -s malloc,256m"

check varnish cli: varnishstat

check varnish listening on port 80: netstat -tulpn (Notice: check varnish listening on port 80 TCP(ipv4) and TCP6(ipv6) )

# netstat -tulpn

Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:25              0.0.0.0:*               LISTEN      646/exim
tcp        0      0 127.0.0.1:6082          0.0.0.0:*               LISTEN      7895/varnishd
tcp        0      0 127.0.0.1:9000          0.0.0.0:*               LISTEN      8543/php-fpm: pool
tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN      25150/mysqld
tcp        0      0 0.0.0.0:587             0.0.0.0:*               LISTEN      646/exim
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      7896/varnishd
tcp        0      0 0.0.0.0:8081            0.0.0.0:*               LISTEN      8135/nginx: master
tcp        0      0 0.0.0.0:465             0.0.0.0:*               LISTEN      646/exim
tcp        0      0 0.0.0.0:1235            0.0.0.0:*               LISTEN      8135/nginx: master
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      637/sshd
tcp6       0      0 :::25                   :::*                    LISTEN      646/exim
tcp6       0      0 ::1:6082                :::*                    LISTEN      7895/varnishd
tcp6       0      0 :::587                  :::*                    LISTEN      646/exim
tcp6       0      0 :::80                   :::*                    LISTEN      7896/varnishd
tcp6       0      0 :::465                  :::*                    LISTEN      646/exim
tcp6       0      0 :::21                   :::*                    LISTEN      5791/vsftpd
tcp6       0      0 :::22                   :::*                    LISTEN      637/sshd
udp        0      0 0.0.0.0:68              0.0.0.0:*                           9023/dhclient
udp        0      0 0.0.0.0:53346           0.0.0.0:*                           9023/dhclient
udp        0      0 0.0.0.0:57953           0.0.0.0:*                           361/avahi-daemon: r
udp        0      0 0.0.0.0:5353            0.0.0.0:*                           361/avahi-daemon: r
udp6       0      0 :::15871                :::*                                9023/dhclient

Restart service (stop nginx before start varnish. If nginx still running, it will keep port 80)

systemctl stop nginx
systemctl restart varnishd
systemctl restart varnishncsa
systemctl restart varnishlog   (By defualt Varnish log directory path is /var/log/varnish/)
systemctl restart nginx

Test Varnish

curl -I http://example.com
HTTP/1.1 200 OK
Date: Wed, 13 Apr 2016 10:58:25 GMT
Content-Type: text/html; charset=UTF-8
Vary: Accept-Encoding, Cookie
X-Pingback: http://example.com
Link: <http://example.com/>; rel=shortlink
Age: 57047
X-Cache: Hit
Connection: keep-alive

Install Vanisher

yum install rubygems
yum install ruby-devel
yum install zlib-devel
yum install libxml2-devel
yum install libxslt-devel
gem install nokogiri
gem install varnisher
gem install bundler

Purge cache

varnisher purge http://example.com/
or
varnishadm "ban req.http.host ~ example.com"
or
curl -X PURGE http://example.com/

Leave a Reply

Your email address will not be published. Required fields are marked *