分类目录归档:个人折腾

PHP & Git 最简单的自动部署

最近比较喜欢用bitbucket,因为要用私有库又不舍得交钱给Github只能这样了,虽然自己也用gitolite搭了git server,但是毕竟仅仅是一个git server。

回到正题,之前的玩法都是开着putty,本地编辑好提交好push上去bitbucket/github,然后putty里面在原地git pull,今天突然想到能不能利用hook简单做个自动部署,稍微看了一下bitbucket的hook文档,bitbucket有个简单的Post Hook(github也有类似的),其实简单的利用这个,都不用出来post过来的关于提交的数据,直接pull就好,于是就有了下面的脚本

然后在仓库的设置那边加个hook,注意看我这里加了简单的http auth,bitbucket是支持的。

这样完事之后发现还不行,因为默认php执行的httpd运行账户是www,一般为了安全都会把web运行账户弄得不能shell登陆(/sbin/nologin或者/bin/false),而且连home目录都没有,为了实现自动部署最好给www一个home,里面要放keys什么的。[11.5补充] 还最好为www用户config一下email和username,不然像bitbucket会说empty ident而无法pull [11.18补充]根据这里,empty ident的问题也可能是因为passwd里面第5个字段为空,最好在第5字段填上东西,是啥不重要

因为httpd什么的都在跑,直接usermod -d肯定说用户已登录改不了,这时候可以用vipw直接修改/etc/passwd,找到没有home(或者home是/dev/null什么的)的可怜的www,给一个home目录给他,shell不用改,保存退出会提示你可以vipw -s来改/etc/shadow保持一致性,这里只改了个home就不必了,后面执行命令可以直接sudo -u www 加命令来以www身份运行。

先sudo -u www mkdir ~/.ssh吧,然后sudo -u www ssh-keygen随便生成个key,不要设置密码,不然git pull困难还得请ssh-agent。生成之后吧id_rsa.pub cat出来加到仓库的部署key,部署key只有只读权限还是挺安全的。

好了之后你可以sudo -u www git pull测试能不能正常pull,能不能pull到,最好这样试一次,因为这里还有个交互是第一次访问要把对方加到known_host里面的,要回答yes,好了之后应该能pull到,web上面的php应该也能调用到git pull并返回信息。这里php后面可以再加别的东西例如针对自动部署的环境做的一些适应性修改、导数据库等工作,注意不要弄出conflict导致下次git pull困难就行。

我喜欢这样随随便便的写,长篇大论的博文我自己都不大愿意看,特别是没干货的东西

 

安全问题还是不容忽视的

之前发生了两个事情,让我觉得有些怕。

第一个事情是上游供应商Hostigation那边坏硬盘,先是说节点挂了,但是数据没有丢失。后面又变成说Raid里面同一个组有两块盘都坏了,所以全部数据丢失,只给你重新开一台VPS,没有赔偿,甚至道歉都没有,去翻看一下TOS果然是自己要为自己的数据负责的。我在他家有两台VPS,还好重要的一台不在那个节点,挂的是我那个拿来实验的一台,万幸。

第二个事情就是SolusVM爆出注入漏洞,这个事情弄得非常蛋疼,漏洞危害程度非常高,Ramnode都因此被人拖库了,还丢了很多客户数据。这是一个开源的服务器控制面板,绝大部分OpenVZ的提供商还有很多其他类型VPS提供商都用这个东西,至少我买过的机器里面只有两家是自己写一个比较鸡肋的面板,大部分都用这个。然后我现在的两个VPS供应商幸好还是没受影响,其中一个到今天还没恢复SolusVM面板的访问。

便宜的东西就是有便宜的东西的坏处,对于我这种长期刷LowEndBox找供应商的人,我用得起的机器都是7刀每个月以下(虽然买了很多台),这类型平价VPS一般都是无管理型,或者说自己管理,不是上游的问题服务商基本不会管你,带管理的套餐多付个25刀左右一个月就有人理你了(高昂的人力成本,硬件相对很便宜)。有的还好一点供应商附送个central备份,但也是手工操作的,没备份就死了。实际上我用的基本上都是完全没有备份的。服务商不提供,我自己也没弄。

但是我知道,数据是无价的,没备份就跟坐车不系安全带一样,你可能一辈子都不出事,但是出事的时候势必都很惨。所以昨天正好LEB上面出来一个Backupsy的备份VPS优惠,我立刻就想出手了,5刀一个月的512 kvm(没用过kvm,我其他机器都是OpenVZ,因为它够便宜),还不算很贵(但是中移动收我30月租我就丫丫丫的骂贵),主打是250G大硬盘,Raid50,。为了防止冲动消费所以我请示了一下后院某人,理解万岁,在我说完购买理由之后她回我”你喜欢就去做吧”,莫名感动。

看了很多文章怎么倒数据库的数据出来啊,怎么rsync啊,怎么增量备份等等,然后就动刀登上久未管理的1号服务器。以前给艳遇配服务器的时候他曾经跟我说你要注意算上那个运维的成本,我也知道。但是一般我这种小机器小需求,长时间load 0 0 0的,经常只是初装那会一顿折腾,折腾好基本就没什么事情了,也不会摊上什么大事,但昨天好像出了点问题。

我登入1号服服务器之后随手看了一下进程,发现有好几个sendmail的进程,而且本地的root用户里面有几百兆的邮件,去查sendmail的日志发现尼玛呀都是垃圾邮件。然后去查下sendmail反垃圾邮件那档事情,大量文章都提到的基本有一点就是不要open relay,就是不要让你的sendmail为匿名的公众转发邮件,其实sendmail后期的版本基本上都关了这个设置的,基本都只能从本机发出去,外部来的邮件不做转发。我重启过sendmail服务,我清空过邮件队列,但是很快又有一堆垃圾邮件进来。我当时还傻乎乎的想去监视一下外网谁在连我的25端口,netstat过几次之后到时傻傻的没看到sendmail只监听了localhost的25端口,没有监听公网,这么说邮件必然是内部发出来的。

内部除了php的环境也基本没什么东西啊,当时在想是不是有人写了发垃圾邮件的脚本,于是找了一个sendmail wrapper的方案,简单的来说就是自己写一个脚本来wrap sendmail,在里面做记录,包括发的什么邮件标题、正文、发到哪里等、还有重要的一个就是env的信息,可以知道是从哪里(工作目录)调用的sendmail,写好这个脚本还要在php.ini里面设置哈。我tail下输出日志终于发现了邮件的源头,居然是来自艳遇的博客(wordpress)的官方主题目录,隐藏的够深的,不过那个目录只有两个文件,有一个help.php看文件名就觉得不对,然后这货居然有执行权限我吓尿了。

打开这个文件略微分析了一下,首先这个文件是混淆过的,非常不好看,但是基本能够看到跟发spam的关系,这个脚本竟然是接收post信息然后发邮件的,还有什么后门我没有详细分析。当时我看这个文件修改时间是3天前,于是我用find全盘查找最近五天修改过的文件,一大堆,但是一点一点排除之后也基本只有这一个有问题的东西。然后去查apache的日志,大片的help.php访问记录,当时我在想必然有个开始,必然是上传或者其他什么写入方式弄好这个后门,再去利用,就想找第一次的访问再看看那之前发生了什么,一找又吓尿了,第一是这个记录条数有17万多,发了多少垃圾邮件啊你妹,哭了。第二是这个文件首次post的记录居然在半个月以前,但是这个文件的修改时间是3天前哦,意味着这个脚本还被更新过或者修改过,倒吸一口凉气。至于访问这个后门的ip,很多,遍布全球,查了5个都不重样的,马来西亚,泰国,荷兰,以色列,斯洛伐克(ip138的数据)。

封了这个东西之后开始全盘找问题,发现问题还真不少,用简单的grep搜索看到好多一句话后门的eval $_post一类的东西,这里插播一个知识,很多人说要禁用eval函数,其实用disable_function是禁不了eval的,因为这不是函数而是一种语法结构,而且还挖到不少是模板系统类的在用eval,正常使用的eval本身问题不大,问题是用eva来执行l一些其他的危险的函数。

再去检查一下发现我的php配置真的是很不安全的说,根本不像一个合格的生产环境,没有disable_function,error也直接输出来,后面一怒之下升级了php版本,打上suhosin,做好应该做的安全设置,其实原来的安全配置也不是一点都没有,php有open_basedir,所以除了艳遇的站其他站都没有受影响,另外服务器是公钥加密登陆的,禁止使用密码登陆。所以服务器这个层次上面倒是没有什么入侵的问题。

晚上一直折腾弄得很夜,显示吧备份弄好了,弄了rsync等还有配套的脚本,然后用各种方法去找客户的网站里面都有哪些后门,这个工作一直弄到今天我才明白了一个道理,然后放弃了。那就是管理,你下面这么多用户这么多网站,你不能保证他们的代码都不出问题,就像一个郭嘉,林子这么大你不能去保证没有坏鸟,你要保证的是就算有人故意干坏事也不能或者尽量少的影响其他人,影响大局。所以我还是专心调教好服务器的安全配置好了,艳遇你的网站见鬼去吧……虽然你说一手把它关掉就行,但是我喜欢折腾寻根问底。而且你都不搞清楚发生了什么事情,难保还原之后问题就不存在了。

白天还折腾了gitolite和owncloud,很有成就感(我是不是又把业务系统弄进备份环境了……),某人说喜欢看我做我喜欢做的事情(拗口),我自己也喜欢看我自己做我自己喜欢做的事情啊。倒是我的复习周啊,一天一天溜走,大家都在复习,我却在这瞎折腾(某人说这是我的天性),浪费时间,罪过罪过。昨天看到一个马斯洛需求的图,哈哈Internet是最底层的需求,这是在说我咩。

续:让nginx支持pathinfo

续上一篇《让nginx支持pathinfo

原文的配置在我本机(Win,Nginx1.2.4)还算可以,但是有一个bug,就是如果url里面包含trailing slash(最后的斜杠/)的话,PATH_INFO捕捉到的值有误,为ATH_INFO,同时$_SERVER数组里面多了一个键名为ORIG_PATH_INFO的元素其值为我们期望的path_info,非常怪异,一开始以为是$path_info变量未定义的问题,$p不见了,剩下ath_info,后面改过变量名之后还是不行,证明不是这个问题。

同样的配置搬到服务器上面用(CentOS6,Nginx1.0.10)完全行不通,根据官方指引(PHPFcgi Common ErrorsNginx Pitfalls)排查无果,再在网上找了许许多多的方案来来回回测试了好几十遍,还是很有问题,而且官方指引(try_files)里面明确指出那种检查文件之后rewrite的方法是terrible的,应该使用try_files代替。

折腾了很久之后还是有各种问题,其实很多PHP框架(如Yii、CI、ThinkPHP)、流行的应用系统(Wordpress、Joomla)等都支持另外一种兼容模式的pathinfo,就是通过其他方法获取path_info值,大部分都通过服务器配置把$request_uri转换为一个queryString参数后转发给index.php,个人目前认为这个方式不太好因为会污染get参数,要注意不要使用保留的get键名,但是如果外部直接在url里面指定该参数不知道会发生什么事。

既然是从$request_uri里面来的,那么直接从$_SERVER[‘REQUEST_URI’]里面提取path_info好了,下面是服务器上面的配置。

location / {
    try_files $uri $uri/ /index.php;
}
location ~ ^.+.php($|/) {
    #fastcgi_split_path_info ^((?U).+.php)(.*)$;
    include fcgi.conf;
    fastcgi_param  PATH_INFO          $fastcgi_path_info;
    fastcgi_param  PATH_TRANSLATED    $document_root$fastcgi_path_info;
    #fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
    fastcgi_pass unix:/tmp/php-cgi.sock;
    fastcgi_index index.php;
}