Nginx ssl_preread传递客户端IP

ssl_preread是基于L4的反代方案,TLS SNI握手时客户端会提供域名,所以可以让Nginx在无需完成TLS握手的情况下,就根据域名进行后端服务器的选择。简单来讲,你只需要给后端服务器配置一个SSL证书,而提供反代功能的Nginx则无需配置。文档见此:http://nginx.org/en/docs/stream/ngx_stream_ssl_preread_module.html

因为这是L4反代,所以通过“proxy_set_header”传递客户端IP的方法是行不通的。其实传递客户端IP的解决办法跟上一篇文章类似:L4(传输层)IP透明反向代理的实现(传递客户端真实IP),nginx也是实现了IP_TRANSPARENT的:https://www.nginx.com/blog/ip-transparency-direct-server-return-nginx-plus-transparent-proxy#ip-transparency,所以,在server里面加上下面一行:

然后按前一篇文章的思路,对路由表进行配置即可。

提醒一下,ssl_preread是配置在stream block下的,放在别的地方,会提示:

所以正确的nginx.conf结构应该如下:

另外,如果在stream中listen了443,http中就无法listen 443了,启动nginx会提示:

可以让http中的server listen loopback地址的另一个端口,让stream中的server proxy_pass这个loopback地址的端口,例如127.0.2.1:8443,然后通过127.0.2.1做策略路由:

然后配置策略路由:

 

『T.S. 89』两个晚来的提高大麦网购票成功率的方法

QQ在线人数统计及其分布图

大家可以看到,那个小亮点数目最多的,最亮的省,是广东省,尤其是珠三角地区!
所以在此提出一个猜测:
在大麦网购票失败的人当中,在广东省购票的人占的比例最大。

也许你会说广东省人多,那购票的人当中,广东省的人所占的比例自然就多,购票失败的广东人占购票失败的人的比例也会多,但你有没有想过为什么呢?

对于大麦网这种网站,要同时应付N多人访问,且保证速度,服务器仅有一台,或仅在一个地区,是不可能的,服务器是分布式的,才能为如此多的访客提供服务(证据:http://www.17ce.com/site/http/201507_a97522b8b50b05c4f2e18c9e579cf1ee.html)。使用分布式服务器,或者CDN,为了能让不同地区的访客均能以最快的速度访问到他们的网站,就要使用NS服务器智能地根据访客的IP给访客返回不同的IP地址(一般是离访客最近的,且ISP相同的)。
由于广东省人多,那同时使用分配给了广东省的服务器的人就多,人多了,服务器就不堪重负,出现拒绝服务的情况,访问人数相对较少的服务器,服务器相对比较空闲,可能仍然有余力处理大量订单。
当然这只是他们的一部分服务器,他们处理订票数据的服务器具体如何部署我不太清楚,但不排除也是分布式的。

所以,下次想提高购票的成功率,访问一个访问人数相对较少的服务器是关键。
想知道哪里人数少,可以使用QQ的在线图作为参考:http://im.qq.com/,点击右上角的“当前在线人数……”。
接下来使用分布式测速服务,例如上面的17ce,还有webkaka,360的。
以上面17ce的测试结果为例,从解析IP所在地字段可以找到许多个省份的服务器,选一个QQ在线图中较暗的省(西藏你不用考虑,因为我目前没见过有公开销售那边的服务器的IDC,所以大麦网使用那边服务器的可能性极低),且要在测试结果的解析IP所在地字段中有该省。

这里我选了黑龙江(选哪个省根据具体情况而定,你不一定要选黑龙江),可以看到有这个服务器:
联通:218.7.220.59

这个省在17ce仅找到了ISP为联通的,可能有些省有多个ISP,不一定要选和你同ISP的,选择同ISP只是可以确保延迟较低,但一般是几个路由,数十毫秒的差距,一般认为南方使用电信的人较多,北方使用联通的人较多,实际使用比例是否如此我就没统计过啦。
接下来编辑hosts文件。
我知道很多人不知道hosts文件是什么,可以点击开始->运行,Windows下输入:

这样就会使用记事本打开hosts文件。
Linux或Unix(Mac OS)的hosts文件在/etc/hosts,自行选择喜欢的编辑器,我喜欢vim,当然你得有root权限。
在末尾新建一行,写入记录(Windows, Linux, Unix均如此):

如图:

hosts

然后保存。由于DNS查询,默认是hosts文件优先(除非你自己改了优先级),因此我们系统获取到shopping.damai.cn的IP将会是218.7.220.59。
验证方法,使用Windows的,在运行的编辑框中输入:

按确定
使用Linux, Unix的,在终端中输入:

按Enter
如果你会nslookup,也可以使用nslookup。
你就可以看到相应的IP,如图:

ping

之后,你访问shopping.damai.cn,就会使用位于黑龙江的服务器。

也许有人留意到了,大麦网有海外的服务器,会不会海外的服务器更少人访问?
这个我是无法确定的,不排除大麦网让所有海外服务器共同使用一个处理订票数据的服务器,甚至该服务器还与国内一个或多个省共用。

毕竟实践是检验真理的唯一标准,因为我没经过测试,只是根据我的理论给出的方案,所以我不敢肯定此方法一定有效。

不过嘛,试试也无妨。

接下来给出另一个方案。
先看看这个图(大家不要生气,我没成功购票,可能是因为我在广东省的原因吧):

Taylor Swift

相信一部分当时盯着大麦网Taylor Swift 1989演唱会的购票页面的人会好奇,为什么倒计时还在进行,我却可以选票,立即预定按钮还出来了?

其实那个日期选择,价格选择,是通过CSS样式禁用了,“您选择了……”,和立即预定按钮,是通过CSS样式隐藏了。
我们可以通过Chrome浏览器的审查元素功能(很多浏览器都有这个功能),修改HTML元素的类,实现更改样式的目的。

找了一会儿,找到一个还没开始售票的项目:http://item.damai.cn/85215.html
我这里就以此项目为例,首先使用Chrome访问该网页。
大家可以发现此页面的时间,票的价格是无法选择的,且“您选择了……”,和立即预定按钮也无法查看到。
把鼠标移动到”2015.07.25 周六 18:00″上,按鼠标右键,点击审查元素,接下来浏览器会弹出一个审查元素的框,并且自动定位到此处的HTML代码,往上数行,可以找到一行的内容为:

如图画红框的位置:

日期选择

编辑此行(可以先用鼠标左键单击此行,此行会变蓝色,再按F2,就会进入编辑状态,或者按右键,选“Edit as HTML”),把:

修改成:

接下来利用相同的方法,定位到价格选择处的代码,不管你是不是要买最便宜的那张票,都给我定位到最便宜的那张票的代码(其实我是想方便你找代码而已),往上数行,找到代码:

如图画红框的位置:

价格选择-1

把:

修改为:

接下来,你可以定位到你要选购的票的面值的HTML代码,如780,往上数行,找到代码:

如图画红框的位置:

价格选择-2

把:

修改为:

不管你是否要选购最贵的一张票,你都给我定位到最贵的一张票的代码处,往下数行,找到代码:

如图画红框的位置:

立即预定

把:

修改为:

到这里,大功告成,可以看到页面已发生了变化:

结果

选择好日期,价格,最后你要做的就是等倒计时结束,就像这图:

Taylor Swift

​别想着你已经选择好了日期以及价格,就可以点击立即预定按钮提交,然后付款购票。
这样只是为了能让你节省一两秒选择日期和价格的时间,还有那该死的Javascript去显示“您选择了……”。

那天我购票仅使用了第二个方法,但提交过去,返回的只是500错误,也许是我没使用第一个方法的缘故吧……

已经确定Taylor Swift要在上海加一场演唱会,如果通过审核,希望这两个方法可以协助各位成功购票。

难得高三毕业了,想去看Taylor Swift的演唱会,却买不到最便宜的票。虽然后面有掉出价格高的,但是学生没那么多钱,广东到上海,路费也不少……

让cPanel/WHM的Apache使用PHP FPM

因为FasiCGI,CGI模式下均有少许问题,所以一直以来都给Apache使用mod_php方式执行PHP。

但此模式的资源占用可要给差评了,在网站访问量大的时候,特别是被CC的时候,FORK出的大量Apache进程经常会变成“僵尸”进程,无法正常退出,即使访问量恢复正常,攻击已结束,那些“僵尸”进程一样占用着你的资源,有时攻击猛烈些,直接整个系统宕掉,非硬重启无法救活。纵使有些人会使用如CloudLinux,BetterLinux之类的限制单用户的进程,但还是会有以Apache默认的执行身份fork出的进程……

为了给虚拟主机带来更稳定,更安全的使用环境,必须更换PHP执行方式!

经过测试与研究,最后采用了PHP FPM。

WHY PHP FPM?

PHP FPM不仅能满足使用admin value,opcache的需求,还能针对每个不同的pool的最大进程数量进行限制。这也就意味着,可以防止某个站点占用服务器过多的资源。

同时,让Apache使用worker模式运行,仅负责静态资源,仅需数个进程就能处理大量的访问。

可见,PHP FPM性能,安全皆具备!

 

很可惜,一直以“强大”著称的cPanel/WHM的,在PHP设置的选项中并没有表现出任何的强大:

Configure PHP and suEXEC

 

 

很明显,这要自己动手了。

 

动手前,先定一个大概的步骤:

1. 切换Apache为worker模式。

2. 编译安装PHP。

3. 给cPanel/WHM添加HOOK。

4. 给已有的用户创建PHP FPM POOL配置文件。

5. 重建所有站点的Apache配置文件。

 

因为服务器有已有虚拟主机的用户,因此“改造”过程中尽量减少Apache的暂停时间。

 

切换Apache为worker模式

看了一下cPanel/WHM编译Apache的的参数,是使用–with-mpm指定mpm模块的,要更换的话,只能重新编译。EasyApache中并未mod_proxy_fcgi,要让Apache使用FastCGI Server,此模块是必须的。

既然如此,那自行编译是最好不过的选择了。

下载Apache,APR,APR-UTILS:

开始编译:

configure的参数,你可以根据自己的需要做出修改。

这里不能重启Apache,否则无法启动了。

编辑/etc/httpd/conf/includes/pre_main_global.conf文件,在里面加入下列代码:

这样,就成功切换Apache为worker模式运行,并启用mod_proxy_fcgi模块。

由于是自行编译的Apache,如果使用/scripts/rebuildhttpdconf,会出现“This tool unavailable until Apache is built by EasyApache 3.x”的提示,编辑/scripts/rebuildhttpdconf文件,把此行:

注释,或者删掉即可。

 

编译安装PHP

这里使用的是PHP 5.4.31:

编译安装,并配置,把下面的代码保存到一个文件,使用“bash 文件名”方式执行

同样的,编译参数你可以自行更改。

 

给cPanel/WHM添加HOOK

根据cPanel/WHM的官方文档,使用HOOK Script实现在成功创建用户后创建PHP FPM的POOL配置文件,以及成功删除用户后PHP FPM POOL配置文件。

编辑/scripts/postwwwacct,加入下列代码:

还有/scripts/postkillacct:

赋予上述文件的执行权限:

 

给已有的用户创建PHP FPM POOL配置文件

用户多的话,手动创建是不可能的,这里提供一个Shell Script:

如果一切无误,启动PHP FPM:

 

重建所有站点的Apache配置文件

先添加一个Apache的用户:

修改cPanel/WHM的Apache配置文件模板,进入/var/cpanel/templates/apache2_4(如果你之前使用的是Apache2.2,应该要进入/var/cpanel/templates/apache2)文件夹,创建自定义配置文件模板:

这样cPanel/WHM就会使用.local结尾的作为模板创建Apache的配置文件。

修改main.local文件,找到此行:

将其更改为:

分别编辑ssl_vhost.local,vhost.local,在文件首行,也就是”<VirtualHost[% FOREACH ipblock IN vhost.ips %] [% ipblock.ip %]:[% ipblock.port %][% END %]>”之前,加入这些代码:

接下来,找到“UserDir enabled [% vhost.user %]”,在他后面三行的“[% END -%]”后加入一行:

如图所示:

ProxyPassMatch

 

完成上述修改后,执行:

重建所有用户的配置文件。

最后,让Apache对配置文件进行检测:

如果出现类似的提示:

那你离成功不远了,访问Configure PHP and suEXEC,把PHP 5 Handler改为none即可:

PHP 5 Handler

一般提交后,WHM会自动帮你重启Apache,不过我这里建议最好还是再使用configtest参数检测一下,并重启Apache。

 

到这里,改造就完成了,可以用雅黑PHP探针对PHP环境进行检测:

雅黑PHP探针

能看到“PHP运行方式”一项为“FPM-FCGI”,那就说明大功告成了。

Nginx与PHP FPM环境下的权限分配与防跨站

相信不少数的网站管理员使用Nginx,并配合PHP FPM运行PHP程序。

之前写过一篇文章,讲述了如何使用ACL权限增强Nginx与PHP FPM环境的安全性,这方法步骤有点麻烦,而且OpenVZ下从物理服务器处挂载为ACL,使用过程中也存在一些问题。

先来讲述一下Nginx与PHP FPM环境下的问题:

服务器上有多个站点,为了安全,我会给每个站点的PHP分配不同的用户身份,因此PHP的执行身份会与Nginx的用户身份不同。

扩展名非.php的文件,会由Nginx去处理,扩展名为.php的文件,Nginx会交给FPM处理,因此Nginx与FPM都需要对文件有read的权限,由于Linux下文件的owner只能是唯一的一个用户,这就使得我必须赋予other对网站文件的读权限。意味着其他身份的用户,也能读取我网站的数据。

很明显,我的服务器是不会允许类似的情况发生。

由于文件所有者只能有一个,因此从这里下手就不太可能解决问题。Other是绝对不能允许拥有任何权限。明显,只能对Group下手。

Linux下的Group,可让多个用户加入至一个Group中,也可让一个用户加入至多个Group。既然如此,把nginx的执行用户加入到站点PHP的执行用户的群组就能完美解决此问题了。

要把用户加入至其他群组,使用usermod即可,其中需要以下参数:

-G:把用户加入至指定群组。

-a:配合-G把用户加入到指定群组,允许用户在不退出原群组的情况下加入至新的群组。

要一个用户加入多个群组,就一定要-a参数啦。

POOL

上图是我服务器其中一个FPM的pool的配置文件,根据配置文件,可看出该网站PHP的运行用户为mediawiki,群组为mediawiki。

我Nginx的执行用户为www-data,执行下面命令,就可以把用户www-data加入至群组mediawiki中:

完成上面的步骤后,把网站文件的所有者和群组改成PHP的运行用户与群组:

然后给予所有者与群组对网站文件的读权限与对目录的执行权限(750或者550),因为我不需要写入权限,因此赋予550就够啦:

这样操作后,即可避免其他用户查看网站的文件。

NOTE:Linux KIT使用此方式分配权限,并可通过lkit快速完成对所有站点的设置。

利用.my.cnf,安全实现Shell下MySQL免输入密码登录

MySQL,相信大家都不陌生,平时也可能会在Linux服务器上使用mysql,mysqldump等登录到MySQL服务器进行操作。

如果直接执行

则会提示输入该用户的密码。

mysql

想一想,如果执行该命令的是cron等非交互式的程序,那到这一步就无法继续。

有人会在-p后接上密码,这是非常不安全的一种做法,万一有用户这时执行ps aux,你的密码就暴露了……

其实,MySQL官方文档有说明,可以在~/.my.cnf处指定用户的密码。

.my.cnf的格式如下:

上面的user一行可以省略,不指定user,则自动以当前Shell登录的用户身份登入mysql。

把上述代码保存到~/.my.cnf,再次输入mysql(或mysql -u 用户名),mysql-client就会自动读取当前用户的家目录下.my.cnf文件的信息,可以无密码自动登入MySQL。

cron等非交互式的程序执行mysql,可能不会自动读取~/.my.cnf,或者.my.cnf保存在其他路径或保存为其他文件名时,就需要使用–defaults-file参数手动指定该配置文件的路径了:

Defaults file

 

最后说一句:一定要保证.my.cnf别的用户/组不能读取(chmod 400)……