让Vranish 传递客户端真实且唯一ip到后置服务器 

首先要说明的是,我的vps是使用varnish作为前置缓存服务器的,后置服务器使用的是nginx 和 hiawatha.前者主要负责 静态文件,而后者则连接php-fpm,处理动态页面.

varnish 监听的是80端口,hiawatha、nginx 分别是81,82.既然有了前置的varnish,自然不想让客户端绕过它直接访问后置服务器,所以我之前做法的是让nginx、hiawatha只监听和允许本地(127.0.0.1、localhost)请求,也就是本地的varnish的请求。

这一点不难做到,通过nginx 的allow、deny 以及 hiawatha 的allowlist 控制符即可达到,见下

#nginx

server {
listen 82;
server_name chinesepaladin.tk;
charset utf-8;
root /home/http/chinesepaladin_tk/;
index index.html index.htm;
allow 127.0.0.1;
deny all;
}


#hiawatha

VirtualHost {
Hostname = chinesepaladin.tk
WebsiteRoot = /home/http/chinesepaladin_tk
StartFile = index.php
UseFastCGI = PHP5
UseToolkit = pw
AccessList = allow 127.0.0.1,deny all
}


而varnish 默认的client ip 就是本身的 server ip(即 127.0.0.1),所以本地访问控制就成功了.

可是,用了一段时间后,问题来了。
由于后置服务器的访客来源都是本地,一直以访客ip作为唯一标识符的wp评分插件——wp-postrating出现问题了,因为来自各个地区的访客都被varnish 标记为了同一个用户——本地访客。

也就是说,一旦有一位访客对某篇文章评了分,之后的其他人都无法再评分了。 囧rz

这个问题很恶心,当我意识到后,我认为很棘手。于是向varnish 邮件列表写了一封求教信,不过收获不大。

终于,在昨天,当我在翻看varnish 的wiki时,我找到了一个大概可行的方案,于是今天我便尝试了一下。

还是与请求对象req有关系,详见下:

if (req.restarts == 0) {
if (req.http.x-forwarded-for) {
set req.http.X-Forwarded-For =
req.http.X-Forwarded-For ", " client.ip;
#req.http.X-Forwarded-For + ", " + client.ip; 不能加'+',报错。
#wiki 里的内容过期了.
} else {
set req.http.X-Forwarded-For = client.ip;
}
}


把上段配置放在vcl_recv()块里面,就行了.这样的话,后置服务器既不会挡掉来自本地的请求,也不会对不通过varnish的请求放行.最重要的是每个访客现在都有了一个唯一的ip来源.

重新读取配置文件,进入控制台
varnishadm -T 127.0.0.1:2000
vcl.load default /etc/sysconfig/varnish/default.vcl
vcl.use default

OK了,评分系统工作正常了。哈哈~

不过高兴没多久,我惊奇的发现使用混合ip的办法,hiawatha居然不认……所有分配给hiawatha的请求依然被无情的挡掉了。我擦~

好在又想到了一个解决方案,就是
1.注释掉hiawatha配置文件里面的所有allowlist.
2.将Binding 块里的Interface 项设成 127.0.0.1,如下

Binding {
Port = 81
Interface = 127.0.0.1 #监听且仅监听 127.0.0.1 地址
MaxKeepAlive = 30
MaxRequestSize = 9999
MaxUploadSize = 10
TimeForRequest = 8,20
}


这样就万无一失了,重启hiawatha.
pkill hiawatha && hiawatha

这次总算成功了。

评论