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替换是非常简单的,参考博客之前分享的文章即可搞定:...
阅读全文
网站建设

利用HSTS安全协议柔性解决全站HTTPS的兼容性问题

导读:目前,很多站都开始实现HTTPS了,而且其中的大部分强迫症站长还会开启强制HTTPS机制,对于网站的HTTP请求全部301跳转到HTTPS,从而实现全站HTTPS。这明显是一个粗暴的做法,下面张戈博客就分享一下目前正在使用的柔性做法,告别粗暴。 一、HSTS协议 这里我们要借助一个新的安全协议:HSTS HSTS(HTTP Strict Transport Security)国际互联网工程组织IETE正在推行一种新的Web安全协议,作用是强制客户端(如浏览器)使用HTTPS与服务器创建连接。 主要目的是为了解决HTTPS网站首次请求时使用的是未加密的HTTP协议,也就说用户一般访问我们的网站都是直接在浏览器输入域名,比如 zhang.ge,然后我们的服务器检测到是HTTP请求,就301跳转到HTTPS页面。那么前半程采用的就是未加密的HTTP请求,同样存在被劫持的可能,那么HTTPS说好的安全性也就大打折扣了! 在我看来,HSTS还有另外一层好处:增强网站的兼容性。 以往分享的全站HTTPS都是采用301强制性跳转,而且还会区分下低版本IE、不支持HTTPS的搜索引擎来忽略301跳转,很明显这样做无法照顾到所有情况。那么如果是用HSTS呢? 采用HSTS后,支持这个协议的浏览器会自动跳转到HTTPS页面,返回码为307: 而不支持HSTS的浏览器访问我们的网站,则不会产生跳转,从而提高了兼容性。这个机制对于不支持HTTPS的搜索引擎来说是非常友好的做法了! 二、开启HSTS 开启HSTS很简单,只要在我们网站的响应头里面新增HSTS即可,下面简单说下 ①、Nginx服务器 只需要在站点server模块内插入如下配置并重启: ②、Apache服务器 Apache如下配置并重启: ③、LigHttpd 将下述配置增加到你的 Lighttpd 配置文件(一般是 /etc/lighttpd/lighttpd.conf)并重启: ④、通用方法 如果你用的虚拟主机,或者不会折腾WEB软件,那么可以采用更简单的通用方法。原理很简单,通过代码来新增响应头即可,这里只分享一下php的做法,其他语言自行参考: 将如下代码插入到网站根目录的index.php即可: 三、相对链接 当然,为了兼容不支持HTTPS的客户端,我们还需要将网站的所有超链接都改成相对模式: 比如,正常的页面链接如下所示: 改成相对模式: 好处就是,不管是HTTP还是HTTPS请求,页面中的地址都是和请求协议保持一致,避免出现页面是HTTP,而页面中的链接却是HTTPS的情况,那么前面的做法也就没了意义。 如何修改为相对模式,估计有同学又玩不转了。万变不离其宗,和以前纯代码启用七牛CDN一样! 直接粗暴替换前台输出的代码即可: 将以上代码新增到 WordPress 主题的functions.php中即可。以上代码只会替换和网站主域名有关系的超链接,八竿子打不着的外部超链接就不管了,有需求自行参考解决。 四、提交HSTS 上文已介绍了HSTS,主要是为了解决HTTP请求301跳转到HTTPS这个过程被劫持问题,而实际上就算加上HSTS响应头,用户请求的前半程依然是HTTP,并没有什么L用。 提出这个协议的砖家们就想出了一个解决办法:将支持HSTS的网站全部加入一个Preload的清单,支持HSTS协议的浏览器请求网站前会查询当前网站是否在清单中,如果是那么直接转换为HTTPS请求!从而解决前半程为HTTP的问题(不专业,但说人话。。。)。 那么,如果我们的网站启用了HSTS,还得将网站提交到这个Preload清单才行了 提交地址:https://hstspreload.appspot.com/  (需要扶墙访问) 提交直到批准,我们的网站必须强制301跳转到HTTPS,否则无法通过,完成审核后再取消301即可。 当然,提交后会显示正在提交到preload list,快的话两三天,慢的话一两个月都是有可能的: 好了,罗里吧嗦分享了一大堆,自行参考吧! 20170205最新补充:经过漫长的等待,偶然查询发现已经是preload状态了,可真不容易:
阅读全文
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了: 事后突然想起,其实自己之前折腾网站的时候其实遇到过同样的问题,就因为没有记录导致重复造轮子。所以这次记录分享一下,权当是备忘吧!
阅读全文