Varnish is a great web application accelerator. Both varnish and nginx can be configured as a httpd cached proxy, but varnish is more advanced in caching (varnish can cache whole page both static and dynamic page), and nginx works better as a web server. Previously I wrote an tutorial How to install and configure Varnish with Apache on Centos 6, but if you want to increase Web Server Scalability, you should switch Apache for Nginx. So I’m make another tutorial how to install and configure Varnish 3 with Nginx 1.6 on Centos 6. I assume you already have a working LEMP (Linux, Nginx, MySQL and PHP-FPM), if not you can follow my another tutorial How to install LEMP web server with Nginx, PHP-FPM 5.5, MySQL 5.5 on Centos Linux.
As of the time I’m writing this tutorial, the latest Varnish Cache release is 4.0.0 but only available in Source version. There is no Debian or Redhat/Centos packages available yet so we are going to use Varnish release 3 for this tutorial.
Install Varnish on Centos 6 Nginx Web Server
Before you isntall Varnish, you will have to install Varnish’s dependencies
# yum update # yum install gcc make automake autoconf libtool ncurses-devel libxslt groff pcre-devel pckgconfig libedit libedit-devel
# rpm --nosignature -i http://repo.varnish-cache.org/redhat/varnish-3.0/el6/noarch/varnish-release/varnish-release-3.0-1.el6.noarch.rpm # yum install varnish
# rpm --nosignature -i http://repo.varnish-cache.org/redhat/varnish-3.0/el5/noarch/varnish-release/varnish-release-3.0-1.el5.centos.noarch.rpm # yum install varnish
# service varnish start
# chkconfig varnish on
Configure Varnish on Centos 6 Nginx Web Server
Default system wide varnish configuration file will be located at “/etc/sysconfig/varnish” and will come with four alternatives. The basic VLC configuration file is located at “/etc/varnish/default.vcl”.
We are going to modify varnish configuration file to make Varnish works in front of Nginx web server on Centos
# nano /etc/sysconfig/varnish
Alternative 3, Advanced configuration is enabled by default, but we are going to use Alternative 2 which is easier to configure. So we are going to disable Alternative 3 and enable Alternative 2. To disable Varnish Alternative 3 configuration, add dash sign (#) before every line in Alternative 3.
Now we are going to enable Alternative 2 by removing dash sign (#) start from “DAEMON_OPTS” line.
By default Varnish listen port 6081 front end. We are going to use Varnish front end and nginx back end. All we have to do is to change Varnish listening port to port 80.
Replace port 6081 to 80 in Alternative 2 from
DAEMON_OPTS="-a :6081 \
DAEMON_OPTS="-a :80 \
## Alternative 2, Configuration with VCL # # Listen on port 6081, administration on localhost:6082, and forward to # one content server selected by the vcl file, based on the request. Use a # fixed-size cache file. # DAEMON_OPTS="-a :80 \ -T localhost:6082 \ -f /etc/varnish/default.vcl \ -u varnish -g varnish \ -S /etc/varnish/secret \ -s file,/var/lib/varnish/varnish_storage.bin,1G"
# nano /etc/varnish/default.vcl
Since we are going to use Varnish front end and Nginx back end. We have to allow both of them to communicate with each other, I’m going to use port 8080 for that task.
Replace port 80
backend default { .host = "127.0.0.1"; .port = "80"; }
backend default { .host = "127.0.0.1"; .port = "8080"; }
sub vcl_recv { if (req.http.host == "domain.com") { set req.http.host = "domain.com"; set req.backend = default; return (lookup); } }
backend namhuy { .host = "127.0.0.1"; .port = "8080"; .connect_timeout = 600s; .first_byte_timeout = 600s; .between_bytes_timeout = 600s; .max_connections = 800; } backend forum { .host = "127.0.0.1"; .port = "8080"; .connect_timeout = 600s; .first_byte_timeout = 600s; .between_bytes_timeout = 600s; .max_connections = 800; } sub vcl_recv { if (req.http.host == "namhuy.net") { set req.http.host = "namhuy.net"; set req.backend = namhuy; # return (lookup); } # set standard proxied ip header for getting original remote address set req.http.X-Forwarded-For = client.ip; # Remove has_js and CloudFlare/Google Analytics __* cookies. set req.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(_[_a-z]+|has_js)=[^;]*", ""); # Remove a ";" prefix, if present. set req.http.Cookie = regsub(req.http.Cookie, "^;\s*", ""); # enable gzip and deflate if (req.http.Accept-Encoding) { if (req.http.Accept-Encoding ~ "gzip") { set req.http.Accept-Encoding = "gzip"; } elsif (req.http.Accept-Encoding ~ "deflate") { set req.http.Accept-Encoding = "deflate"; } else { # unkown algorithm remove req.http.Accept-Encoding } } # logged in users must always pass if( req.url ~ "^/wp-(login|admin)" || req.http.Cookie ~ "wordpress_logged_in_" ){ return (pass); } # accept purges from w3tc and varnish http purge if (req.request == "PURGE") { return (lookup); } # don't cache phpmyadmin if (req.url ~ "^/phpmyadmin") { return (pass); } # don't cache search results if( req.url ~ "\?s=" ){ return (pass); } # always pass through posted requests and those with basic auth if ( req.request == "POST" || req.http.Authorization ) { return (pass); } # else ok to fetch a cached page unset req.http.Cookie; return (lookup); # don't cache phpbb if (req.http.host == "forum.namhuy.net") { set req.http.host = "forum.namhuy.net"; set req.backend = forum; return (pass); } } # accept purges from w3tc and varnish http purge sub vcl_hit { if (req.request == "PURGE") { purge; } return (deliver); } # accept purges from w3tc and varnish http purge sub vcl_miss { if (req.request == "PURGE") { purge; } return (fetch); } sub vcl_pass { return (pass); } sub vcl_fetch { # don't cache phpmyadmin if (req.url ~ "^/phpmyadmin") { return (hit_for_pass); } # remove some headers we never want to see unset beresp.http.Server; unset beresp.http.X-Powered-By; unset beresp.http.Age; # only allow cookies to be set if we're in admin area - i.e. commenters stay logged out if( beresp.http.Set-Cookie && req.url !~ "^/wp-(login|admin)" ){ unset beresp.http.Set-Cookie; set beresp.ttl = 48h; } # Don't cache error pages if (beresp.status == 404 || beresp.status == 503 || beresp.status >= 500){ set beresp.ttl = 0s; } # allow phpbb if (req.http.host == "forum.namhuy.net") { set req.http.host = "forum.namhuy.net"; set req.backend = forum; return (hit_for_pass); } } sub vcl_deliver { # add debugging headers, so we can see what's cached if (obj.hits > 0) { set resp.http.X-Cache = "HIT"; } else { set resp.http.X-Cache = "MISS"; } # remove some headers added by varnish unset resp.http.Via; unset resp.http.X-Varnish; unset resp.http.Age; } sub vcl_hash { hash_data(req.url); if (req.http.host) { hash_data(req.http.host); } else { hash_data(server.ip); } return (hash); }
Configure Nginx to work with Varnish on Centos 6
We are done with Varnish part, the next thing we are going to do is to make Nginx to work with Varnish. By default nginx listens on port 80 as a web server, but in our case we have Varnish caching in front of Nginx. We have changed Varnish to listen to port 80, and use port 8080 to talk to Nginx. We have not configured Nginx to talk to Varnish yet but we are going to do it.
# nano /etc/nginx/conf.d/default.conf
Default default.conf file should look like
server { listen 80; server_name localhost;
Server { listen 127.0.0.1:8080; server_name domain.com;
# service nginx restart # service varnish restart
# curl -I http://domain.com
HTTP/1.1 200 OK Server: nginx/1.6.0 Content-Type: text/html Last-Modified: Thu, 24 Apr 2014 13:33:03 GMT ETag: "5359128f-264" Content-Length: 612 Date: Mon, 05 May 2014 03:34:51 GMT X-Varnish: 1267017339 1267017337 Age: 5 Via: 1.1 varnish Connection: keep-alive