WEB应用

分享一个Nginx正向代理的另类应用案例

最近接到了一个需求:通过Nginx代理把现网一个自研代理程序给替换掉,感觉有点意思,也有所收益,简单分享下。 需求背景 部门的生产环境异常复杂,有部分第三方引入的系统位于特殊网络隔离区域,请求这些系统需要通过2层网络代理,如图所示: 中心源系统请求目标系统API的形式各异,我简单收集了下,至少有如下3种: 目前开发GG是用 lighthttp 二次开发实现了这个需求(猜测用到了一堆判断和转发逻辑),存在一定的后期维护工作量,而且这个GG已经转岗去其他部门了,现任开发GG就想直接通过 Nginx 代理来实现,淘汰这个组件,因此就将这个需求丢给了我这个运维了。 需求分析 拿到需求后,我分析了下,应该需要使用正向代理来实现,我们来看下普通的一级正向代理写法: 这个规则的意思是将所有请求都代理到请求对应的主机。这个在内网正向代理上网的时候会用到,这时候用户只需要将你提供的代理设置为http_proxy,就可以访问到直接访问不到的站点。 看起来好像可以满足需求了,But...实际需求是要经过2层代理,那第一层代理的$host必须是固定为第二层代理的地址了!而且Nginx也不支持类似http_proxy的设置,所以照搬正向代理是行不通的。 最终解决 既然正向代理涉及到自动提取目标主机、端口以及请求的特性,那我们就自己设计一个请求方式,方便使用Nginx自带规则来提取并自动代理。 我和开发约定了一个请求方式(之前也用了类似约定),方便Nginx来提取变量并自动代理: 将真正需要请求的API拆成: ?schema=http&host=主机:端口&proxy_url=请求路径及参数,然后请求到第一级Nginx代理服务,一级代理将请求原样传给Nginx二级代理,然后在二级代理上通过正则提取schema、host和proxy_url,并代理请求,即可满足需求。 Nginx一级代理规则(反向代理):反向代理到2个二级代理 Nginx二级代理规则(正向代理):自动提取url里面约定的协议、目标主机和url并代理 最后再套了一层负载均衡,最终生产环境的拓扑如下: 利用Nginx代理,非常轻量的替代了之前开发GG研发的程序,而且后期维护工作量基本可以忽略不计,其中涉及到的安全措施这里就略去不提了,请自行脑补。
阅读全文
WEB应用

解决网站404页面返回200状态码问题

好久没打理博客,突然收到CDN流量预警,发现平均每天40G流量消耗!what?就现在这个访问量,不存在的。看了下CDN日志发现有小人一直在请求博客页面,其中被请求最多的就是CCkiller防御工具那个文章地址。 呵呵,我就写一个简单的防御小工具,惹着你啦?实际上我用了CDN,也并没有安装这个工具,所以想试探、想测试效果的麻烦自己去安装使用,攻击我博客毫无意义,挂了又能怎么样? 废话就扯这么多,进入正题。 看日志的时候,我发现有大量请求到了博客其实并不存在的地址,但是返回码居然是200??这就不正常了,于是手工访问了一下一个不存在的页面,虽然WordPress在前台给我展示了一个404页面,但是浏览器显示返回码确实是200!!纳尼? 还以为WordPress更新后改了这个机制呢,把主题下的404.php加了一个强行的404返回码,发现没有任何效果。 最后发现,居然是自己以前把404页面静态化留下的坑! 原因很简单,当时经常有人攻击一些不存在的页面,也就是每次都是动态的404,服务器自然就容易高负载,因此做了一个静态化处理: 通过curl请求一个不存在的地址,触发404返回内容,然后保存在网站的某个目录下,比如xxxx下面: 然后,在Nginx Vhost下新增404响应规则: 重启Nginx之后,再访问不存在的博客页面的时候,Nginx就直接返回404.html的内容了,从而实现404页面的静态化。 但是,Nginx这里我写错了,导致每次返回404.html都是200返回码!!这样其实会误导搜索引擎的判断,以为页面是存在的。。。。大坑。 正确的Nginx配置方法应该是: 也就是不用等号,而是用空格!修改后,重启Nginx,然后访问不存在的地址发现已经是404返回码了,问题解决!
阅读全文
WEB应用

Nginx内容替换模块http_substitutions_filter_module及实用案例分享

说到Nginx的内容替换功能,大部分人应该都听说过Nginx内置的的subs_filter替换模块,但是这个模块有个缺憾,就是只能替换一次,而且还不支持正则表达式,这就有些鸡肋了。 不过,我们可以集成一个第三方的替换模块:ngx_http_substitutions_filter_module,来实现我们的各种需求。 经过测试,这个模块至少有如下实用功能: ①、支持多次替换 ②、支持正则替换 ③、支持中文替换 Ps:略有遗憾的是,这个替换不能使用到 if 判断模块内,否则就超神了。。。 下面,简单介绍下 ngx_http_substitutions_filter_module 的安装实用以及一些实用案例。 一、编译集成 和所有Nginx非内置模块一样,添加模块需要在编译的时候指定模块源码包来集成。当然,Tengine可以使用动态模块加载的功能,这里就不细说了。 ①、下载模块源码包并解压,最后列出目录位置备用 github手动下载地址:https://github.com/yaoweibin/ngx_http_substitutions_filter_module/ ②、在服务器上执行 nginx -V 查看当前  Nginx 编译参数,比如: ③、加上模块参数,重新编译Nginx 找到服务器上原来安装时留下的 Nginx 源码目录(如果没有请重新下载并解压,此处不赘述),进入目录后,在第②步中的参数基础上新增集成替换模块(请注意前面需要加上  ./configure ): ./configure --add-module=/root/ngx_http_substitutions_filter_module-master/ 例如: 再往后,则是make以及平滑升级,请参考之前的文章完成: Nginx在线服务状态下平滑升级或新增模块的详细操作记录 正确完成后,Nginx就具备内容替换功能了。 二、使用说明 模块的github主页其实已经有了很详细的说明了,这里就简单的做下搬运工。 使用示例: 从github给出的使用示例来看,这个模块涉及2个指令: * subs_filter_types subs_filter_types 语法: subs_filter_types mime-type 默认: subs_filter_types text/html 适用: http, server, location subs_filter_types 是用来指定替换文件类型的 默认仅仅替换text/html类型的文件。   * subs_filter subs_filter 语法: subs_filter source_str destination_str 默认: none 适用: http,server,location subs_filter 是用来替换文本的,可以使用正则 g(默认):替换匹配项。 i  :区分大小写的匹配 o : 只匹配发现的第一个。 r  : 正则匹配。 三、案例分享 ①、全站https 有了这个功能,要实现全站https也就是非常简单了,只要把本站的http://协议代码全部替换成https即可。当然,替换时要注意匹配范围,免得把不支持https的外链也一起替换了。。。 比如,将如下代码添加到网站Nginx配置内即可完成替换 ②、CDN域名替换 这个模块在CDN方面同样简单实用!比如,我们网站要用到七牛CDN,不管是纯代码还是插件,那都是靠PHP代码来进行替换的,性能肯定就不如Nginx直接替换来的简单粗暴了。 Ps:经测试,在使用正则模式时,不能使用nginx内置变量,比如:$host,否则会出现如下报错: nginx: match part cannot contain variable during regex mode in *** ③、解决前台暴露管理员账号风险 前段时间,看到有博客在说 WordPress 会在前台暴露管理员登陆账户的问题,然后给出了较为复杂的解决办法:通过修改 WordPress 内核函数来隐藏账户名。 修改内核函数,一般是非常无奈,没有其他解决方法的时候才会用到,所以,我看到这个问题第一件时间想到的办法就是替换。 使用PHP替换是非常简单的,参考博客之前分享的文章即可搞定:...
阅读全文
WEB应用

解决Nginx配置http2不生效,谷歌浏览器仍然采用http1.1协议问题

昨天一个网友通过QQ联系我,说按照我博客之前分享的http2配置教程不能生效,想请我帮忙看看。 经过测试,使用谷歌浏览器访问他的测试站点,确实没有开启http2,但他的配置和编译参数都正确的,这有点奇怪了。 不过昨天太忙就没有继续帮他分析,他只好将服务器账号和密码都留言给了我。今天中午我抽空在他服务器重新编译测试了一把,才发现原来是这么一个梗! 他在编译Nginx之前,使用的是yum安装的openssl,可能是他的yum源太陈旧,或者没配置EPEL导致yum安装的openssl版本过低!而他在编译Nginx的时候并没有使用--with-openssl=DIR的选项来静态编译,所以他编出来的Nginx用的系统低版本的openssl,导致谷歌访问时并不会开启http2! 找了段专业解释如下: Chrome 在最近的更新中放弃了对 NPN 的支持,如果想要继续在 Chrome 上支持 HTTP/2 ,则需要安装最新 1.0.2 版的 OpenSSL,并且用 1.0.2 的 OpenSSL 重新编译 Nginx。 参考资料: 新版Chrome下滚回HTTP/1.1 Supporting HTTP/2 for Google Chrome Users 所以,解决方法就非常简单了,从openssl官网下载最新源码包,然后新增如下参数重新编译即可: --with-openssl=源码包解压目录 比如: 当然,我们也可以先更新yum源,比如改用EPEL源,使用 yum update openssl 升级后重新编译。这里我个人建议使用源码静态编译。 重新编译安装后,再利用谷歌浏览器访问如下网址: 测试他的网站已经成功开启http2了: 事后突然想起,其实自己之前折腾网站的时候其实遇到过同样的问题,就因为没有记录导致重复造轮子。所以这次记录分享一下,权当是备忘吧!
阅读全文
网站建设

分享一个网站防镜像以及解决七牛静态页面跳转的js方案

导读:作为站长,基本都遇到过网站被人镜像的烦恼吧?最典型的代表就是谷歌搜索,大家都懂的。很多时候反代我们网站的人可能就是拿你的网站练下手,学习下反向代理。当遇到网站被反代,而且排名还比你好的时候,有没有要暴走的冲动...本文分享一种简单有效网站防镜像的方案,适合任何html页面。 一、前人分享 挺早之前,看到boke112转载过一篇网站防镜像教程,分享了从.htaccess、php以及js三个方向禁止他人恶意反向代理我们的网站。当时看完觉得三个方法都不完善: 先分析下原理: .htaccess方案是禁止从代理IP过来的请求 js方案如果发现浏览器url地址不是预期的,那么直接跳转到我们规定的域名。 php方案的原理和js方案类似,通过 $_SERVER 变量判断域名判断请求是否符合预期,不是就跳转走。 再分析下缺憾: .htaccess方案,只要请求中含有代理IP(HTTP_X_FORWARDED_FOR不为空)就禁止访问,那如果用CDN的就全部GG了,而且这个值是可以在做反向代理的时候置空的,比如Nginx中可以这样做: php方案中,$_SERVER的值同样可以在反向代理时伪造,比如: 二、优化版本 已推出最终版,所以,此优化版本可以不用了 js方案,这个也是我今天要分享的方案,之前在boke112我也留言分享了张戈博客的做法,不过好像留言被删除了。文章中的js方案可是可以,但是是写死的跳转。也就是说不管在哪个页面,最终跳转都是首页!显然,这个方案还不够精细化,我们可以做得更细致! 所以,网站防镜像最简单有效的做法就是在<head>部分插入如下js代码即可: 这里对文章js方案做了更细致的改善,也就是跳转之前想将当前url做一次替换,把当前url中的域名换成我们规定的域名,确保跳转后就是用户想要的页面,而不是强硬的跳到首页! js方案相对于其他方案来说,它的优势在于无法在反代时伪造,浏览器反馈的就是真实的访问情况,直接粗暴。当然,用 Nginx 的第三方内容过滤模块 ngx_http_subs_filter_module 也可以对反代的页面内容进行过滤,当然这是更高级的手法了,这里就不深入介绍了(请注意这段话,本文分享的只是一个方案,并非绝对有效的方法!!)。 三、最终版本 ①、WordPress专用版 龙笑天下很好的整理总结了目前几种防镜像的js方案,我看到最后一个借助了img的onerror事件,想法不错,就重新写了一个更简洁,兼容性更好的代码: 将此代码添加到主题functions.php文件当中即可。其他类似js可以不用上了,不过也不会冲突。 Ps:本来是丢到wp_head的,经过测试发现图片放到head,浏览器会自动进行错误调整,导致一些本来在head的元素被丢到了body当中,比如style.css,估计网页标准中head里面就不应该放置图片,所以移到了footer当中。 2017年10月21日补充:这段代码会因为onerror死循环造成浏览网页的电脑高负载(CPU飙升),因此在代码onerror触发事件中加入onerror清空机制,即加入this.onerror=null【相关文章】。 ②、HTML通用版 既然是js代码,那么肯定可以用于任何符合html规范的页面了。要不是为了可以放到wp的functions.php,都没必要写成php的模式,直接用html代码即可: 将以上代码中的 自行拆分成自己的域名,避免被镜像代码替换掉,比如: 然后将代码添加到网站的<body>之后即可(不建议放置到<head>里面,具体原因上文已说明),WP一般为header.php文件,其他建站程序请自行搞定,这个版本适合任何网页。 ③、通过UA禁止 JS版本效果确实可以,但是有一个小弊端,大部分搜索引擎不能识别js,所以蜘蛛还是能正常抓取镜像网站,有可能会影响SEO。要彻底解决镜像站问题,就得直接禁止镜像网站服务器抓取我们的网页。 有网站已经分享了通过获取镜像网站的服务器IP来禁止抓取,但是镜像网站换一个IP,或者还有其他镜像网站,都无法一劳永逸。所以,我们可以研究镜像服务器抓取时的特征,然后通过禁止特征来解决镜像问题,当然这个方法也不能绝对,因为特征很多时候都是可以伪造的,这里就不多说了。 14年张戈博客就就已经整理分享过网站反爬虫攻略:《服务器反爬虫攻略:Apache/Nginx/PHP禁止某些User Agent抓取网站》,其实这种镜像站和采集基本类似,所以我们需要先分析某一类镜像站的UA特征是什么。 抽空对此次站长朋友纷纷“讨伐”的几个镜像站进行了分析,其实就是在访问镜像网页的时候去查看我们的网站日志,我发现全部请求UA都是PHP/5.4.4: 想来也就明白了,这些镜像站点基本都是用的一套程序,甚至环境都是一致的!这让人很容易联想是不是一个人在搞事。。。 好了,废话不多说,既然知道他们的UA了,那么就很好解决了。直接将 PHP这个关键词加入到《服务器反爬虫攻略:Apache/Nginx/PHP禁止某些User Agent抓取网站》 这篇文章的UA清单中即可! 这里,只简单分享一下PHP代码和Nginx代码,其他的请参考前文。 PHP通用版: 将以上代码加入到PHP网站根目录的index.php的<?php 之后即可。 WP适用版: 如果使用上面的php版本,WordPress每次更新就会需要操作index.php,比较麻烦,因此弄个专版: 将以上代码添加到WordPress主题的functions.php中即可。 Nginx版本: 将以上规则加入到nginx的vhost当中,比如添加到第一个location 之前,然后重载Nginx即可。 我看到有同学使用了htaccess来判断UA,但最后却返回了一个301跳转到首页,虽然也可以,但是有时候镜像程序也是可以抓取301的目标内容的,至少我之前就写过支持301跳转的php代码。 好了,关于镜像网站的问题就整理分享这么多,大家自行选择适合自己的方案即可! 四、拓展延伸 另外,如果是使用https的网站,想将 http 的访问都跳转到 https 又不想弄个301跳转(可能影响SEO),那么上述js代码稍微改改就能完美跳转了: 看到这,你应该体会到了js的妙用吧?后续应该可以举一反三,多多利用了! 五、七牛镜像 用了七牛的网站,可以试试直接访问我们自定义的七牛静态域名,是不是和我们现在的网站一模一样呢?只是它不会更新而已。很多人肯定下意识的试过张戈博客,发现居然会跳转到对应的博客页面! 比如访问:http://static.zhang.ge/5100.html 会跳转到 https://zhang.ge/5100.html 于是,有不少朋友留言问我,怎么实现301跳转的?? 好吧,除非七牛帮忙在CDN节点做设置,将非静态资源请求都跳转到源站,否则张戈也是没办法做301跳转的。因此,你看到的跳转也不是301了,而是js的跳转! 实现原理就是上文介绍的js方案咯!七牛就类似于一个镜像站,而且是静态存储到了七牛节点,因此只能用js方案,在静态页面中实现判断和跳转。 所以,上文分享的js防镜像代码,同样适用于七牛静态页面的自动跳转。只是美中不足的是,大部分搜索引擎并不能识别这个跳转,为了SEO,那你还得继续使用七牛的robots设置了。 当然,如果你添加js代码之前就已经在使用七牛了,那么必须清空七牛中的缓存文件才行,否则是不会跳转的了!因为缓存的代码中没有这段js咯! 最新补充:有人留言说了更好的方案,在Nginx中判断七牛的UA以及抓取的路径就能杜绝七牛缓存不改缓存的页面,要实现也很简单,在Nginx配置中加入如下规则即可: 最后,再啰嗦一句,本文分享的只是小白入门级方案,喜欢喷的朋友建议早点Alt +F4,张戈谢谢你。
阅读全文