十、$document_uri 表示访问的url
需求是:访问 www.abc.com 请求到 www.abc.com/abc/
在nginx配置文件中加入:
if ($document_uri !~ 'abc') { rewrite ^/(.*)$ /abc/$1 permanent; }
而不是单独加一句
rewrite ^/(.*)$ http://www.abc.com/abc/$1 permanent;
如果只加rewrite 规则,而不限定条件,那么会造成死循环。 会访问到 http://www.abc.com/abc/abc/abc/abc/....
十一、nginx的301与302如何配置
首先看一个完整代码示例,关于nginx 301 302跳转的。
301跳转设置:
server { listen 80; server_name 123.com; rewrite ^/(.*) http://456.com/$1 permanent; access_log off; }
302跳转设置:
server { listen 80; server_name 123.com; rewrite ^/(.*) http://456.com/$1 redirect; access_log off; }
在看下关于nginx 301 302跳转的详细说明文档:
server { server_name test.com; rewrite ^/(.*) http://www.test1.com/$1 permanent; }
last – 基本上都用这个Flag。
break – 中止Rewirte,不在继续匹配
redirect – 返回临时重定向的HTTP状态302
permanent – 返回永久重定向的HTTP状态301
Nginx的重定向用到了Nginx的HttpRewriteModule,下面简单解释以下如何使用的方法:
rewrite命令
nginx的rewrite相当于apache的rewriterule(大多数情况下可以把原有apache的rewrite规则加上引号就可以直接使用),它可以用在server,location 和IF条件判断块中,命令格式如下:
rewrite 正则表达式 替换目标 flag标记
flag标记可以用以下几种格式:
last – 基本上都用这个Flag。
break – 中止Rewirte,不在继续匹配
redirect – 返回临时重定向的HTTP状态302
permanent – 返回永久重定向的HTTP状态301
特别注意:
last和break用来实现URL重写,浏览器地址栏的URL地址不变,但是在服务器端访问的路径发生了变化;
redirect和permanent用来实现URL跳转,浏览器地址栏会显示跳转后的URL地址;
例如下面这段设定nginx将某个目录下面的文件重定向到另一个目录,$2对应第二个括号(.*)中对应的字符串:
location /download/ { rewrite ^(/download/.*)/m/(.*)\..*$ $1/nginx-rewrite/$2.gz break; }
nginx重定向的IF条件判断
在server和location两种情况下可以使用nginx的IF条件判断,条件可以为以下几种:
正则表达式
如:
匹配判断
~ 为区分大小写匹配; !~为区分大小写不匹配
~* 为不区分大小写匹配;!~为不区分大小写不匹配
例如下面设定nginx在用户使用ie的使用重定向到/nginx-ie目录下:
if ($http_user_agent ~ MSIE) { rewrite ^(.*)$ /nginx-ie/$1 break; }
文件和目录判断
-f和!-f判断是否存在文件
-d和!-d判断是否存在目录
-e和!-e判断是否存在文件或目录
-x和!-x判断文件是否可执行
例如下面设定nginx在文件和目录不存在的时候重定向:
if (!-e $request_filename) { proxy_pass http://127.0.0.1; } return
返回http代码,例如设置nginx防盗链:
location ~* \.(gif|jpg|png|swf|flv)$ { valid_referers none blocked www.test.com www.test1.com; if ($invalid_referer) { return 404; } }
十二、nginx rewrite不支持if 嵌套也不支持逻辑or和逻辑and的解决方法
如题,apache的rewrite是支持或者的,用个OR就可以,如果不加OR,多个RewriteCond 罗列累加就是并且的意思。然后nginx的rewrite就没有这么好了。那么如何去实现这样复杂的功能呢?这就用到了标记功能。
现在出一个简单的需求: 要求访问uri以 /abc/开头的请求,并且user_agent带有ie6或者firefox关键词的请求需要禁止访问。
实现方法为:
set $rule 0; if ($document_uri ~ '^/abc') { set $rule "${rule}1"; } if ($http_user_agent ~* 'ie6|firefox') { set $rule "${rule}2"; } if ($rule = "012") { deny all; }
这样就可以实现了。
然后在我实践过程中,发现一个问题,就是如果定义超过3条rule,当条件中包含两条和两条以上的规则同时存在是,需要把两条规则的条件写到第4条规则前面。
例如,有一个这样的需求:实现rewrite的总前提是,所有请求必须以^/abc 目录为开头。其余规则如下:
1. user_agent 包含 'ipone' 或者'ipad' 或者'ipod' 的请求需要把 *htm 转发为 *html;
2. user_agent 不包含 'ipone' 或者'ipad' 或者'ipod' 并且user_agent 包含'ucweb'的请求需要把*htm 转发为 *html;
3. user_agent 不包含 'ipone' 或者'ipad' 或者'ipod' 并且user_agent 不包含'ucweb'的请求需要把*html 转发为 *htm;
规则语句为:
set $rule 2; if ($document_uri ~* '^/abc') { set $rule "${rule}1"; } if ($http_user_agent ~* 'ipad|iphone|ipod') { set $rule "${rule}2"; } if ($rule = "212") { rewrite ^(.*)\.htm$ $1\.html redirect; } if ($http_user_agent !~* 'ipad|iphone|ipod') { set $rule "${rule}3"; } if ($http_user_agent !~* 'ucweb') { set $rule "${rule}4"; } if ($http_user_agent ~* 'ucweb') { set $rule "${rule}5"; } if ($rule = "2134") { rewrite ^(.*)\.html$ $1\.htm redirect; } if ($rule = "2135") { rewrite ^(.*)\.htm$ $1\.html redirect; }
注意,上面规则把 $rule = "212" 放到了上面,如果放到下面则不能实现跳转。
十三、nginx 代理
如果一个网站无法访问,就像是国外的youtube,如果有一台美国vps,那么可以在vps的nginx加入以下配置做proxy,当然这个只是理论上可以,因为现在的墙太强大了,肯定是不行的!!!
server { listen 80; server_name www.baidu.com; ## 想要访问的网站地址 location / { proxy_pass http://180.97.33.108/; ## 百度的DNS地址 }
设置好了重启nginx服务,然后执行curl -x127.0.0.1:80 www.baidu.com -I,如果返回的状态码是200说明代理成功,然后在需要使用代理服务的机器上的hosts文件中加入:192.168.1.5 www.baidu.com 192.168.1.5为你的代理服务器IP地址
让局域网不能上外网的机器通过nginx代理服务上网
在vhosts目录下新建一个 shangwang.conf的配置文件
添加以下内容:
server{ resolver 8.8.8.8; ## DNS地址,可以 cat /etc/resolv.conf 查看 listen 8002; ## 监听端口,不要和默认的web服务80端口冲突,不然直接跳转到nginx服务器默认的web页面上去了. location / { proxy_pass http://$host$request_uri; ## 默认即可 proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; allow 192.168.1.0/24 ## 可以只允许某个IP段使用代理 deny all; ## 然后deny掉其它所有 } }
代理的使用(客户端的设置):
linux 机器,执行:
vim /etc/profile export http_proxy=http://192.168.1.5:8002 ## 192.168.1.5是nginx服务的ip,8002是监听端口 source /etc/profile
windows 机器,在IE选项中选择 - 连接 - 局域网设置 - 配置代理服务器,将相应IP,监听端口填入即可
十四、根据访问的目录来区分后端的web
需求: 当请求的目录是 /aaa/ 则把请求发送到机器a,当请求的目录为/bbb/则把请求发送到机器b,除了目录/aaa/与目录/bbb/外,其他的请求发送到机器b
upstream aaa.com { server 192.168.111.6; } upstream bbb.com { server 192.168.111.20; } server { listen 80; server_name li.com; location /aaa/ { proxy_pass http://aaa.com/aaa/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location /bbb/ { proxy_pass http://bbb.com/bbb/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location / { proxy_pass http://bbb.com/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
说明:
1 以上配置文件中的 aaa.com 以及 bbb.com 都是自定义的,随便写。
2 upstream 中的server 可以写多个,例如
upstream aaa.com { server 192.168.111.6; server 192.168.111.4; server 192.168.111.5; }
proxy_pass http://aaa.com/aaa/ 这里必须要加这个目录,不然就访问到根目录了。
实际上,上述配置文件中, localtion /bbb/ 部分是可以省略掉的,因为后边的 location / 已经包含了/bbb/,所以即使我们不去定义 localtion /bbb/ 也是会访问到 bbb.com 的。
十五、针对请求的uri来代理
场景:1台nginx去代理4台apache
需求:根据不同的请求uri 代理到不同的apache
upstream aa.com { server 192.168.0.121; server 192.168.0.122; } upstream bb.com { server 192.168.0.123; server 192.168.0.124; } server { listen 80; server_name www.abc.com; location ~ aa.php { proxy_pass http://aa.com/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location ~ bb.php { proxy_pass http://bb.com/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }