Apache + Varnish + nginx 获取正确的客户端IP

本文发布已超过一年,其中的内容可能已经过时。

貌似现在只要我更新博客就说明又在没事瞎折腾了… =.=
很久以前就遇到过这个问题,或者不如说实际上就是因为无法正确获取客户端IP才让我一直用的 Apache + nginx 的构架。今天折腾一下午 + 一晚上总算是把这个问题(还算)圆满地解决掉了。

首先是参考这篇文章配置好整个服务器构架,后端使用 Apache httpd 来处理 PHP, 中间用 Varnish 做缓存,前端使用 Tengine 作为 web 服务器,所以来自客户端的请求的处理流程是:

Client -> Tengine:80 -> Varnish:8090 ->(Miss)-> httpd:81

然后问题就来了,处在最后面的 httpd 拿不到正确的客户端IP地址,总是显示为127.0.0.1. 这个问题有趣在于,一直以来我都是使用了 mod_rpaf 来获取 X-Forwarded-For 中的客户端IP的,而如果我去掉中间那一层 Varnish 直接让 Tengine/nginx 反向代理给 httpd 的话,IP地址是能够正确获取的,更进一步实验表明,在只有一次代理的情况下一切都是正常的,当代理变成了两层,无论两层代理的顺序如何,都会出现这个问题。

中间各种股沟各种查文档就[此处省略6小时]了…

基本上有两个比较主要的原因。

1. X-Forwarded-For 在经过了多个代理服务器后会变成一个IP列表,形如:X-Forwarded-For: client, proxy1, proxy2
2. mod_rpaf 只会从 X-Forwarded-For 列表的最右侧取出IP地址,所以代理超过一层的时候就无法取到客户端IP而是把上一层代理的IP当成客户端了。

解决办法也很简单,从 2.3 版开始,Apache 官方提供了一个 mod_remoteip 模块,而且在 2.4 版本中已经默认集成并开启。而对于 2.2 版本,也有第三方自制的兼容版本

参照说明编译安装好模块:

完成过后,在 httpd.conf 中加上:

别忘了把 mod_rpaf 的给去掉避免冲突。

如果你和我一样是拿 ArchLinux 做生产环境的倒霉孩子(呵呵),也可以直接用我打的AUR包: https://aur.archlinux.org/packages/mod_remoteip/

最后重启 httpd 使模块载入即可。

{ 发表评论? }

  1. Liu, Sizhuang Mozilla Firefox Linux

    你的博客的URL真有趣……

  2. laogui Google Chrome Windows

    感谢楼主,两行代码就帮我解决了问题,网上很多方法都过时了,修改这修改那的,其实apache现在很强大了,大部分还在用老版本。

回复 laogui 取消回复

您的电子邮箱地址不会被公开。 必填项已用*标注