近日,针对公司生产环境的PHP网站服务应用主机进行了单点安全隐患的技术改造,将单一主机上的nginx+php-fpm应用迁移至了一套haproxy/keepalived+nginx+php-fpm的双机负载均衡系统中去。
实测,一切问题都烟消云散。
haproxy监听HTTP和HTTPS端口,对公网提供服务。
nginx+php-fpm分别在两个应用主机上部署,处理haproxy分发来的访问请求。nginx监听8080提供HTTP服务,监听8081端口提供HTTPS服务。
1、
在实际测试中,使用浏览器通过域名访问集群上的网站服务,如http://abc.example.com/ 。浏览器打开网页超时,且地址栏返回的URL变成了:http://abc.example.com:8080/xxx/index.php 。
在使用HTTPS协议访问时,也同样超时,且URL中出现了8081的端口。
考虑到我们是使用两个主机部署的全套haproxy/keepalived+nginx+php-fpm的应用,且haproxy的工作网段与nginx处在相同网段。而nginx又使用了自定义的服务端口。所以才会产生了这种问题,即haproxy把访问请求分发给了nginx,但nginx在返回响应时却在URL中携带了自已的服务端口。恰恰haproxy和nginx使用的端口是不同的,因此产生了以上故障。
关于以上分析,可以使用firefox的firebug插件进行网络跟踪,比较容易看到nginx返回的响应头带上了自己的8080或8081的端口号。
带着这个疑问在网上搜索了下相关资料,于是看到了nginx的port_in_redirect选项。这是一个使用在nginx.conf的http段落中的配置项。功能是决定nginx在响应访问请求时,时否在响应头中加上自己的服务端口号,默认开启。
于是调整为 port_in_redirect off;
重启服务后,除phpmyadmin之外的全部项目都可以正常访问了。
2、
在使用http或https访问phpmyadmin服务时,仍然会超时,仍然在拿到的HTTP响应中URL地址被添加了nginx的服务端口。
使用Wireshark在本机抓包,分析访问phpmyadmin时的本机收发数据包,不有任何发现。
登录nginx应用主机,使用tcpdump对服务器端的haproxy和nginx服务地址、端口进行抓包,分析数据通信流向,仍然没有任何发现。
虽然其它我们公司自行研发上线的php项目都已经可以正常浏览和使用了,但phpmyadmin继续固执得在返回HTTP响应时带上了NGINX的服务端口。
于是,转而怀疑是phpmyadmin源码存在问题。忽然想起之前在网上查阅这方面资料时,偶然看到有人提到过php在使用一个环境变量SERVER_PORT时的注意事项。因此,我猜想phpmyadmin在使用该环境变量时,是不是存在问题。
进入到phpmyadmin的应用目录,执行:
$find . -name "*.php" | xargs grep SERVER_PORT
找到了这个文件:
./libraries/Config.class.php
if (empty($url['port']) && PMA_getenv('SERVER_PORT')) {
$url['port'] = PMA_getenv('SERVER_PORT');
}
从字面意思上,就能理解为,这个判断条件是phpmyadmin对url地址进行了判断,如果url中没有明确使用端口且本地HTTP Server中定义了服务端口,那么就把url中的端口号设置为本地Http Server服务的端口中号!
终于找到了为什么phpmyadmin固执得返回nginx的8080和8081服务端口的原因了。
果断把上面的判断逻辑修改为:
if (empty($url['port']) && PMA_getenv('SERVER_PORT')) {
// $url['port'] = PMA_getenv('SERVER_PORT');
if ( PMA_getenv('SERVER_PORT') == 8080 ) {
$url['port'] = 80;
} elseif ( PMA_getenv('SERVER_PORT') == 8081 ) {
$url['port'] = 443;
}
}
实测,一切问题都烟消云散。