最近搞了个海外的阿里云主机后,就把自己的个人站迁移了。然后就想办法做优化,用上了openresty + php7 + http2。 因为历史原因,自己搞了几个不同的域名,一个是fukun.org,还有一个之前一直用的digdeeply.org,现在想统一起来,可是却发现wordpress里有很多上传附件的时候,链接已经是写死的,使用的当时的域名digdeeply.org,如果去一个一个的把他们替换过来,就不太现实了。 因为自己用过openresty中的lua,所以首先想到的就是使用一个content_by_lua来实现替换,在这个阶段把内容中字符串替换掉,不过有个细节问题就是这里lua拿到的都是nginx的一个一个的chunk,如果想要替换的字符串正好在两个chunk的分界处,那么这个就会被漏掉而不能替换。 然后在查一些资料的时候,突然发现,其实,nginx自己就有支持字符串替换的模块的: sub_filter , 这样就不用自己在lua写了,会更方便一些,那么先来看看sub_filter怎么用吧。 location / { sub_filter ‘https://fukun.org'https://fukun.org'; sub_filter ‘https://fukun.org'https://fukun.org'; sub_filter_once off; } 用法很简单,只要使用 sub_filter ‘search’ ‘replacement’ ,把被替换和替换内容给出来就可以了,可以写多条规则,替换多次。 其它的几个参数稍微看下文档也能明白了: 语法: sub_filter_once on | off; 默认值: sub_filter_once on; 配置段: http, server, location 字符串替换一次还是多次替换,默认替换一次。如果全文中有多个查找到的字符串,希望全部替换的话,就开启这个选项。 语法: sub_filter_types mime-type …; 默认值: sub_filter_types text/html; 配置段: http, server, location 指定需要被替换的MIME类型,默认为“text/html”,如果制定为*,那么所有类型的内容都会被替换,我们其实一般来说,只希望替换text/html中的就可以了,因为如果是图片啥的,你想替换啥呢? 如何安装sub_filter功能模块http_sub_module 以上是sub_filter的用法,但是如果你已经安装好nginx服务了,而且之前没有安装sub_filter模块,那怎么办呢,总不能把nginx全部重新编译重装吧,那样会覆盖之前的nginx配置,还得再来配置一遍。 可以用另外一种方法来更新nginx,那就是只从新编译,而不安装。就是只执行 ./configure 和 make 方法,而不执行make install,这样就不会有问题了。然后把make编译好的nginx二进制文件拷贝到已安装的nginx sbin目录下覆盖之前的,覆盖之前请做好备份,并停止当前运行的nginx。 我是用的openresty,所以很多configure的参数不用自己加,第一次我编译的时候,因为需要http2和status模块, 只执行了: ./configure –prefix=/home/s/apps/openresty-1.9.7.1 –with-http_v2_module –with-http_ssl_module –with-luajit –with-http_stub_status_module 现在需要sub_filter功能,所以只要添加–with-http_sub_module就可以了。那么就是这么编译:
阅读全文

nginx referer限制

语法:valid_referers [none|blocked|server_names]

使用字段:server, location

这个指令在referer头的基础上为 $invalid_referer 变量赋值,其值为0或1。

可以使用这个指令来实现防盗链功能,如果valid_referers列表中没有Referer头的值, $invalid_referer将被设置为1。

参数可以使如下形式:

none 意为不存在的Referer头(表示空的,也就是直接访问,比如直接在浏览器打开一个图片)

blocked 意为根据防火墙伪装Referer头,如:“Referer: XXXXXXX”。

server_names 为一个或多个服务器的列表,0.5.33版本以后可以在名称中使用“*”通配符。

举例:

location /chat/ { 
  valid_referers none blocked so.com *.so.com; 
  if ($invalid_referer) { 
    return 403; 
  } 
} 


阅读全文

最近的谈谈项目使用了部分lua,用于一些请求量超高的请求,在nginx层面挡回去,省的调用大量php进程。

由于以前没用过lua,开发过程中遇到了一些小技能点,记录一下。

1.lua字符串分割函数

--字符串分割函数,按|分割
 function lua_string_split(str, split_char)
     local sub_str_tab = {};
     for mu_id in string.gmatch(str, "(%d+)|*") do
         table.insert(sub_str_tab, mu_id)
     end
     return sub_str_tab;
 end
 --字符串分割函数END

2.使用lua的reids 的 批量获取方法。 比如:hmget

先将所有的field整合到一个Table, 比如: field_table里。

redis:hmget(key,  unpack(field_table))


阅读全文

nginx if判断 and 使用

360图片搜索遇到这么一个场景,pc端的搜索结果页和频道列表页,在移动端访问时,检测到是移动版的ua,会自动跳转到对应的移动端结果页或频道列表页。

现在,pc端新上了一个频道,服饰频道,但是移动端还没开发。当在移动端访问pc版的服饰频道页时,会跳转到移动端的频道页,但是没有服饰频道,所以跳转到了默认的美女频道,体验不好。

所以,就需要做一个处理,当发现是服饰频道时,不跳转,保持pc端的展示。

之前的nginx配置是判断ua后,就决定是否跳转。

if ($http_user_agent ~* "^((.*android.*)|(.*Mobile Safari.*)|(.*windows phone os.*)|acer|zte|lenovo|moto|samu|nokia|sony|kindle|240x320|mobile|mmp|ucweb|midp|pocket|psp|symbian|smartphone|treo    |up.browser|up.link|vodafone|wap)") {
         rewrite "^/$"              http://m.image.so.com/ permanent;
         rewrite "^/([z|i])$"       http://m.image.so.com/$1 permanent;
     }

现在需要对频道页判断,而由于频道页是通过参数传入,而不是在path里边,所以使用rewrite规则无法解决。

其实就可以使用$request_uri判断就可以了。本来是打算在if里通过 and 或者 && 解决,结果发现不支持。

查了资料后,发现一个方便实现的方法,通过两次判断,设置变量的形式。

如下:

if ($http_user_agent ~* "^((.*android.*)|(.*Mobile Safari.*)|(.*windows phone os.*)|acer|zte|lenovo|moto|samu|nokia|sony|kindle|240x320|mobile|mmp|ucweb|midp|pocket|psp|symbian|smartphone|treo    |up.browser|up.link|vodafone|wap)") {
         set $mobile 1;
     }
     if ($request_uri ~* ".*ch=fushi.*"){
         set $mobile 0;
     }
     if ($mobile = 1){
         rewrite "^/$"              http://m.image.so.com/ permanent;
         rewrite "^/([z|i])$"       http://m.image.so.com/$1 permanent;
     }


阅读全文

今天在压测时,会偶尔遇到错误,错误提示: Cannot assign requested address ,看了下,大致上是由于客户端频繁的连服务器,由于每次连接都在很短的时间内结束,导致很多的TIME_WAIT,以至于用光了可用的端 口号,所以新的连接没办法绑定端口,即“Cannot assign requested address”。是客户端的问题不是服务器端的问题。通过netstat,的确看到很多TIME_WAIT状态的连接。 解决办法是需要做一下内核参数优化:(需要root权限) sysctl -w net.ipv4.tcp_timestamps=1 开启对于TCP时间戳的支持,若该项设置为0,则下面一项设置不起作用 sysctl -w net.ipv4.tcp_tw_recycle=1 表示开启TCP连接中TIME-WAIT sockets的快速回收 改完还不能解决问题,需要修改tcp_max_tw_buckets sudo sh -c “echo ‘5000’> /proc/sys/net/ipv4/tcp_max_tw_buckets”
阅读全文

在做以图搜图时,需要用户上传图片,同时需要对用户上传图片做大小限制。 如果文件全部上传到服务器了,可以用$_FILES变量来获取文件信息,判断文件大小,来决定是否拒绝用户的请求。 不过当文件过大时,会直接出发nginx的413 Request Entity Too Large 错误,如何友好的来提示用户呢。 这里就可以用到nginx的error_page用法了,直接指定413的错误跳转到一个指定页面,在指定页面内友好提示即可。 在做以图搜图时,需要用户上传图片,同时需要对用户上传图片做大小限制。 如果文件全部上传到服务器了,可以用$_FILES变量来获取文件信息,判断文件大小,来决定是否拒绝用户的请求。 不过当文件过大时,会直接出发nginx的413 Request Entity Too Large 错误,如何友好的来提示用户呢。 这里就可以用到nginx的error_page用法了,直接指定413的错误跳转到一个指定页面,在指定页面内友好提示即可。 这样设置了之后,就可以使用了,当上传的文件过大时,会直接被nginx拦截到413错误,进而重定向到友好的错误提示页。 不过在一次bug修复之后,发现再提交过大的文件时,没有出现这个提示页面了,而是等了很长时间之后出现了一个500错误,而且500错误也没有被拦截到50x的错误页面,很是奇怪。排查了下nginx日志,出现的错误提示就是 client intended to send too large body: 4224579 bytes. 排查了一会之后,再测试环境下打开错误输出,发现原来是413重定向后的Action在视图里有php语法错误。修复之后,就又恢复正常啦。 client intended to send too large body
阅读全文

作者的图片

DigDeeply

Technology Stack: PHP/Openresty/GoLang, and so on…

Web Develop Eneigneer

Beijing China