使用Varnish代替Squid做网站缓存加速器的详细解决方案[原创]
nginx在使用varnish作缓存情况下获取用户真实ip
http://yaozb.blog.51cto.com/2762349/840297
前言:在网站架构当中,使用varnish缓存服务器为网站做缓存,后端再使用lnmp架构已经是很平常的事情了,但是,在很多种情况下,后端的nginx服务器,无法获取到用户的真实ip.日志中总是记录着前端的varnish服务器ip。这也让一些站长很烦恼。其实nginx有这种功能的。下面我就来讲解一下,如何让nginx在使用varnish做缓存的情况下获取到用户的真实ip。
我们先弄两台测试机器
- A:192.168.1.151 服务: varnishd
- B:192.168.1.150 服务: nginx
一,我们先安装好这两个服务。
1..在A服务器上安装varnishd
- # yum install pcre*
- # wget http://repo.varnish-cache.org/source/varnish-3.0.0.tar.gz
- # tar -xvf varnishd-3.0.0.tar.gz
- # cd varnish-3.0.0
- # ./configure --prefix=/usr/local/varnishd
- # make&&make install
2,在B服务器上安装nginx
- # yum install pcre*
- # wget http://soft.vpser.net/web/nginx/nginx-1.0.10.tar.gz
- # cd nginx-1.0.10/
- # ./configure --user=www --group=www --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_gzip_static_module --with-ipv6 --with-http_realip_module
- # make && make install
这里在nginx安装时,添加了一个 --with-http_realip_module 的模块来获取真实ip.
这样我们就在两台服务器上分别安装好了这两个服务。
二.关于一些基本配置
这里我直接在varnishd配置文件里,加上一个缓存的网站
www.yaozhibingceshi.com ,配置文件如下:
- #Cache for linuxtone sites
- #backend vhost
- backend wwwyaozhibingceshicom {
- .host = "www.yaozhibingceshi.com";
- .port = "80";
- }
- #acl
- acl purge {
- "localhost";
- "127.0.0.1";
- "192.168.0.0"/24;
- }
- sub vcl_recv {
- if (req.http.Accept-Encoding) {
- if (req.url ~ "\.(jpg|png|gif|jpeg|flv)$" ) {
- remove req.http.Accept-Encoding;
- remove req.http.Cookie;
- } else if (req.http.Accept-Encoding ~ "gzip") {
- set req.http.Accept-Encoding = "gzip";
- } else if (req.http.Accept-Encoding ~ "deflate") {
- set req.http.Accept-Encoding = "deflate";
- } else {
- remove req.http.Accept-Encoding;
- }
- }
- if (req.http.host ~ "(.*)yaozhibingceshi.com") {
- set req.backend = wwwyaozhibingceshicom;
- }
- else {
- error 404 "This website is maintaining or not exist!";
- }
- if (req.request == "PURGE") {
- if (!client.ip ~purge) {
- error 405 "Not Allowed";
- }
- #.dd.....
- return(lookup);
- }
- #...GET...url...jpg,png,gif. ..cookie
- if (req.request == "GET"&& req.url ~ "\.(png|gif|jpeg|jpg|ico|swf|css|js|html|htm|gz|tgz|bz2|tbz|mp3|ogg|mp4|flv|f4v|pdf)$") {
- unset req.http.cookie;
- }
- #..GET...url.php....cache....
- if (req.request =="GET"&&req.url ~ "\.php($|\?)"){
- return (pass);
- }
- # }
- #........pipe..
- if (req.request != "GET" &&
- req.request != "HEAD" &&
- req.request != "PUT" &&
- req.request != "POST" &&
- req.request != "TRACE" &&
- req.request != "OPTIONS" &&
- req.request != "DELETE") {
- return (pipe);
- }
- #..GET .HEAD.....
- if (req.request != "GET" && req.request != "HEAD") {
- return (pass);
- }
- if (req.http.Authorization) {
- return (pass);
- }
- return (lookup);
- }
- #..url+host hash......
- sub vcl_hash {
- hash_data(req.url);
- if (req.http.host) {
- hash_data(req.http.host);
- } else {
- hash_data(server.ip);
- }
- return (hash);
- }
- # .....purge .....
- sub vcl_hit {
- if (req.request == "PURGE") {
- set obj.ttl = 0s;
- error 200 "Purged";
- }
- return (deliver);
- }
- sub vcl_fetch {
- if (req.url ~ "\.(jpeg|jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg|ico|swf|flv|dmg|js|css|html|htm)$") {
- set beresp.ttl = 2d;
- set berespberesp.http.expires = beresp.ttl;
- set beresp.http.Cache-Control = "max-age=172800";
- unset beresp.http.set-cookie;
- }
- if (req.url ~ "\.(dmg|js|css|html|htm)$") {
- set beresp.do_gzip = true;
- }
- if (beresp.status == 503) {
- set beresp.saintmode = 15s;
- }
- }
- sub vcl_deliver {
- set resp.http.x-hits = obj.hits ;
- if (obj.hits > 0) {
- set resp.http.X-Cache = "HIT You!";
- } else {
- set resp.http.X-Cache = "MISS Me!";
- }
- }
并在A服务器的host文件里绑定
www.yaozhibing.com 为 192.168.1.150
- # vim /etc/hosts
- 192.168.1.150 www.yaozhibingceshi.com
启动varnish
- # /usr/local/varnishd/etc/varnish/vcl.conf -s malloc,10M -T 127.0.0.1:2000 -a 0.0.0.0:80
B服务器上的Nginx 可参考网上一些配置,都是大同小异的,
我在这里添加一个虚拟主机:
- # vim /usr/local/nginx/conf/nginx.conf
- server
- { listen 80;
- server_name www.yaozhibingceshi.com;
- index index.php index.html index.htm;
- root /home/yaozhibing;
- log_format wwwlogs '$remote_addr - $http_x_real_ip - $http_X_Forwarded_For - $remote_user [$time_local] "$request" ';
- access_log /home/yaozhibingceshi.log wwwlogs;
- }
我们在日志文件里定义了 $http_real_ip, $http_X_forwarded_for的值,其实这两个值是一样的。 http_real_ip是指用户的真实ip。$http_X_forwarded_for是指通过上一级代理之前的ip。如果有多级代理,这个值里面就有很多的ip.我们这里只有一级代理,所以。这里的$http_X_forwarded_for 指的也是用户的真实ip.
很明显这些值,是获取不到的,只能获取到前端varnishd服务器 192.168.1.151的ip.
三,配置varnishd,让nginx获取到真实用户的ip.
那么现在我们来整一下varnish的配置。让varnish把$http_real_ip和$http_X_forwarded_for值传给nginx.
我们在A服务器的varnish配置文件里的sub vcl_recv 里面加入以下这段:
- remove req.http.X-real-ip;
- set req.http.X-real-ip = client.ip;
- set req.http.X-Forwarded-For = client.ip;
意思就是获取用户的真实ip 即 client.ip 并赋值给 http.X-real-ip 和 http.X-Forwarded-For。
现在的varnishd配置文件为:
- #Cache for linuxtone sites
- #backend vhost
- backend wwwyaozhibingceshicom {
- .host = "www.yaozhibingceshi.com";
- .port = "80";
- }
- #acl
- acl purge {
- "localhost";
- "127.0.0.1";
- "192.168.0.0"/24;
- }
- sub vcl_recv {
- #此处为添加内容
- remove req.http.X-real-ip;
- set req.http.X-real-ip = client.ip;
- set req.http.X-Forwarded-For = client.ip;
- if (req.http.Accept-Encoding) {
- if (req.url ~ "\.(jpg|png|gif|jpeg|flv)$" ) {
- remove req.http.Accept-Encoding;
- remove req.http.Cookie;
- } else if (req.http.Accept-Encoding ~ "gzip") {
- set req.http.Accept-Encoding = "gzip";
- } else if (req.http.Accept-Encoding ~ "deflate") {
- #以下略。。
这下我们获取到了我本机的真实ip。192.168.1.5,但是我们从定义的日志格式来看,这个值应该是 http.X_Forwarded_For 的值。当有多级代理的时候,这个值不能代表用户的真实ip.但是我在varnishd确实把http_real_ip传过来了啊,为什么不能显示呢。这下,我们用要用到nginx的 http_realip_modul这个模块了。接下来,我们在nginx里,做一下设置,来获取 real_ip.
四:修改nginx配置文件,来获取用户真实ip.
Nginx 的http_realip_modul很好用。在nginx里定义一下从哪获取值。获取哪个值。就OK 了,
我们把虚拟主机的配置文件修改成下面这样的:
- server
- {
- listen 80;
- server_name www.yaozhibingceshi.com;
- index index.php index.html index.htm;
- root /home/yaozhibing;
- location / {
- set_real_ip_from 192.168.1.151;
- real_ip_header X-Real-ip;
- }
- log_format wwwlogs '$remote_addr - $http_x_real_ip - $http_X_Forwarded_For - $remote_user [$time_local] "$request" ';
- access_log /home/yaozhibingceshi.log wwwlogs;
- }
也就是在虚拟机主机的配置文件里,添加了:
- location / {
- set_real_ip_from 192.168.1.151;
- real_ip_header X-Real-ip;
- }
set_real_ip_from 是定义获取的源,就是从哪里获取值
real_ip_header 是定义获取哪个值。
我们看到,http.X_real_ip 和 http.X_Forwarded_For的值。都能正常显示了。
如果不想看到上级代理的值。在nginx配置文件里把 log_format 的 $remote_addr去掉就可以了。
日志还能添加更多内容,这里我们只看ip,所以把日志简化写的。