1. 概述

大家都知道Nginx有很多功能模块,比如反向代理、缓存等,这篇文章总结下我们这些年实际环境中那些有用的Nginx规则和模块,大部分是用法的概括及介绍,具体细节在实际配置时再自行google。

2. 内置语法

先介绍Nginx默认已支持的内置功能,靠这些基本就满足大部分的web服务需求。

2.1 proxy代理

proxy常用于两类应用场景,一类是中转,如异地科学的上网方式,另外一类是到后端服务的负载均衡方案。

用反向代理时候,需要特别注意里面的域名默认是在nginx启动时候就解析了,除非reload否则一直用的是当初解析的域名,也就是说不能动态解析。

但这个问题是可以通过别的模块或者用内置字典变量方式来解决。

  1. resolver 114.114.114.114;
  2. server {
  3.    location / {
  4.        set $servers github.com;
  5.        proxy_pass http://$servers;
  6.    }
  7. }

2.1.1 中转

针对某个域名进行中转:

  1. server {
  2. listen 172.16.10.1:80;
  3.    server_name pypi.python.org;
  4.    location ~ /simple {
  5.        proxy_set_header Host $http_host;
  6.        proxy_redirect off;
  7.        proxy_pass http://pypi.python.org;
  8.    }
  9. }

注意如果是前后端域名不一样的话需要处理proxy_redirect的301跳转之类的显示,否则在跳转时候会跳转到proxy_pass的域名。

另外可以直接代理所有80端口的http流量:

  1. server {
  2.    listen 80;
  3.    server_name _;
  4.    resolver 114.114.114.114;
  5.    set $URL $host;
  6.    location / {
  7.        proxy_pass http://$URL;
  8.    }
  9. }

如果是想代理https的站点也不是不可能,只是需要自行处理CA证书导入即可,而且经过https中转的流量对nginx是透明的,也就是有证书的时候做窃听和劫持的情况。

2.1.2 负载均衡

这是代理的另外一个常见用法,通过upstream到多个后端,可以通过weight来调节权重或者backup关键词来指定备份用的后端,通常默认就可以 了,或者可以指定类似ip_hash这样的方式来均衡,配置很简单,先在http区域添加upstream定义:

  1. upstream backend {
  2.    ip_hash;
  3.    server backend1.example.com weight=5;
  4.    server backend2.example.com weight=5;;
  5. }

然后在server里面添加proxy_pass:

  1. location / {
  2.    proxy_pass http://backend;
  3.    proxy_http_version 1.1;
  4.    proxy_set_header Connection "";
  5. }

做负载均衡的时候可以智能识别后端服务器状态,虽然可以智能地proxy_next_upstream到另外的后端,但还是会定期损失一些正常的“尝试性”的连接,比如过了max_fails 次尝试之后,休息fail_timeout时间,过了这个时间之后又会去尝试,这个时候可以使用第三方的upstream_check模块来在后台定期地自动探索,类似这样:

  1. check interval=3000 rise=2 fall=5 timeout=2000 type=http;

这样替代用户正常的连接来进行尝试的方式进一步保障了高可用的特性。

还有就是在做前端代理的时候也是这样的方式,直接proxy_pass到后端即可,比如CDN的场景。

2.2 防盗链

普通的防盗链是通过referer来做,比如:

  1. location ~* \.(gif|jpg|png|bmp)$ {
  2.    valid_referers none blocked *.example.com server_names ~\.google\. ~\.baidu\.;
  3.    if ($invalid_referer) {
  4.        return 403;
  5.    }
  6. }

再精细一点的就是URL加密,针对一些用户IP之类的变量生成一个加密URL通常是针对文件下载时候用到,可以通过openresty来写lua脚本或者是accesskey之类的模块来实现。

2.3 变量

nginx里面支持正则匹配和变量配置,默认的变量比如remote_addr、request_filename、query_string、server_name之类的,这些组合在一起可以做很多规则,或者还有日志里面status、http_cookie等。

还有在进行多域名配置时候可以用通配符,比如:

  1. server_name ~^(www\.)?(.+)$;
  2. root /data/web/$2;

这样就实现了自动进行域名的目录指派。

变量方面,比如配置变量a=1:

  1. set $a 1;

下面这个案例配合if判断来做有更大的用处。

2.4 if判断

nginx里面支持一些简单的if判断,但是没有多重逻辑的语法,多个判断条件用起来需要结合变量的方式来实现,比如允许ip地址为10.10.61段和和192.168.100段的用户访问,其余的拒绝,返回405状态码:

  1. set $err 0;
  2.    if ( $remote_addr ~ 10.10.61.){
  3.        set $err 0;
  4.    }
  5.    if ( $remote_addr ~ 192.168.100.){
  6.        set $err 0;
  7.    }
  8.    if ( $err = 1){
  9.        return 405;
  10.    }

这样通过一个err变量比较巧妙实现了需求。

2.5 error_page

有用到后端proxy的地方需要加上这句话才可以传到状态码到nginx:

  1. fastcgi_intercept_errors on;

具体配置一般是配置到具体的错误URL页面,比如:

  1. #返回具体状态码
  2. error_page 404 403 /4xx.html
  3. #返回200状态码
  4. error_page 404 403 =200  /error.html

或者采用callback的方式统一做处理:

  1. error_page 404 403 = @fallback;
  2. location @fallback {
  3.    proxy_pass http://backend;
  4.    access_log /data/logs/404_error.log access;
  5. }

这样在重定向时不会改变URL,然后把404页面直接返回。

2.6 rewrite

rewrite做一些301、302之类的跳转,同时也可以在CDN前端做“去问号”缓存的效果。

  1. location /db.txt {
  2.    rewrite (.*) $1? break;
  3.    include proxy.conf;
  4. }

另外最常见的跳转写法:

  1. rewrite ^/game/(.*) /$1;

把/game/test跳转为/test的效果,注意这样是没有状态码的,如果访问正常就直接返回200状态码。

可以在后面加个permanent参数,就变为了301 Moved Permanently,或者添加redirect改为302跳转。

同理,还可以进行多个正则匹配进行URL重组,比如:

  1. rewrite ^/download/(.*)/lastest/(.*)$ /file/$1?ver=$2 break;

2.7 日志字段

想针对每个连接进行日志留档,可以在nginx日志那里配置好字段,比如记录cookie之类的数据。

在log_format字段里面加入$http_cookie变量即可。

另外post的数据可以永久保留在文件里面,比如用来做http的日志备份,包括get和post的原始数据,把这个值开启即可:

  1. client_body_in_file_only  on;

然后post的数据就会保存在nginx/client_body_temp文件夹里面。

2.8 internal关键词

这个关键词很少见,但有时候是很有用的,比如在有很多规则时候,突然需要针对某个目录转为nginx内部处理。

  1. location ^~ /upload/down/ {
  2. alias /data/web/dts/dtsfile/down/;
  3. internal;
  4. }

2.9 try_files

字面意思是尝试,后面可以接多个目录或者文件,比如kohana框架:

  1. try_files $uri /index.php?$query_string;

先看是否有URL这个文件,没有的话再调用index.php来处理,或者支持状态码处理:

  1. try_files /foo /bar/ =404;

没有这两个文件的话返回404状态。

2.10 auth认证

可以做简单的用户登录认证方式,其中的passwd_file得通过apache的htpasswd命令来生成。

  1. auth_basic "Restricted";
  2. auth_basic_user_file passwd_file;

认证通过之后每次访问会在头部添加Authorization字段包含用户名密码的base64加密密文给服务端。

2.11 gzip

普通的线上web站点gzip压缩是必须要开的,压缩一些文本类型的文件再返回给用户。

注意必须手动指定全需要压缩的类型,比如css、js之类的,线上配置如下:

  1. gzip on;
  2. gzip_min_length  2048;
  3. gzip_buffers     4 16k;
  4. gzip_vary   on;
  5. gzip_http_version 1.1;
  6. gzip_types  text/plain  text/css text/xml application/xml application/javascript application/x-javascript ;

2.12 mime配置

很久以前基本是忽略这个配置,但手游流行之后就发现异常了,需要让手机浏览器知道返回的apk后缀是什么类型,否则类似IE浏览器会以zip后缀返回,需要加上:

  1. application/vnd.android.package-archive apk;
  2. application/iphone pxl ipa;

2.13 限速

限速包括限制请求的并发数和请求的下载速度。

简单的限制某个线程的下载速度就直接加上一句话就可以了:

  1. limit_rate 1024k;

要限制某个IP的并发数之类的就需要用ngx_http_limit_req_module和ngx_http_limit_conn_module模块了,不过是默认就编译好的。

比如使用一个 10M 大小的状态缓存区,针对每个IP每秒只接受20次的请求:

  1. limit_req_zone $binary_remote_addr zone=NAME:10m rate=20r/s;

2.14 location匹配

location匹配有多种方式,常见的比如

  1. location  = /
  2. location  /
  3. location ^~ /test{

是有优先级的,直接 ”=” 的优先级是最高的,一般就用”~”这个符号来匹配php就好了,不过是区分了大小写的:

  1. location ~ .*\.php$

2.15 文件缓存

返回给用户的文件一般都配置了过期时间,让浏览器缓存起来。

比如缓存14天:

  1. expires 14d;

针对某些特殊的文件就需要location匹配之后进行禁止缓存配置:

  1. add_header Cache-Control no-cache;
  2. add_header Cache-Control no-store;
  3. expires off;

2.16 缓存文件

nginx可以作为ATS这样的缓存服务器来缓存文件,配置也比较简单,不过我们很少用,除非一些特殊的场合,参考配置:

  1. #先在全局下面定义好缓存存放的目录
  2. proxy_cache_path  /data/cache/ levels=1:2 keys_zone=cache_one:10m inactive=7d max_size=10g;
  3. proxy_temp_path   /data/cache/proxy_temp_path;
  4. proxy_cache_key   $host$uri$is_args$args;
  5. #然后在server里面的location匹配好目的文件,加入下一段即可
  6. proxy_cache cache_one;
  7. proxy_cache_valid 200 304 24h;
  8. proxy_cache_valid any 10m;
  9. proxy_pass https://$host;
  10. proxy_cache_key $host$uri$is_args$args;
  11. add_header  Nginx-Cache "$upstream_cache_status"; 3. 内置模块

3. 内置模块

nginx含有大量的模块可以支持多种复杂的需求,比如源码目录src/http/modules里面就有很多c模块的代码,或者直接通过./configure –help|grep module来查看有哪些内置模块,编译时候直接加上就可以了。

除了nginx内置的模块,网络上还有很多第三方的模块,可以通过编译时候加参数–add-module=PATH指定模块源码来编译。

下面介绍一些我们线上用过而且比较赞的内置模块。

3.1 stream

端口转发的模块,从nginx1.9版本才开始支持,包含tcp和udp的支持,和IPTABLES相比这个虽然是应用层,会监听端口,但是配置起来很方便,比IPTABLES灵活,在tcp模块下面添加类似vhost的server就可以了,方便自动化管理,参考配置:

  1. server {
  2.    listen PORT;
  3.    proxy_pass IP:PORT;
  4.    access_log /data/logs/tcp/PORT.log;
  5. }

3.2 http_realip_module

nginx反向代理之后,如何让后端web直接获取到的IP不是反向代理的iP,而是直接获取到用户的真实IP呢,就需要这个模块了,不需要代码那里再做类似X-Real-IP的变量特殊判断。

3.3 http_slice_module

在做CDN时候可以用到,让一个大文件分片,分成多个小文件通过206断点续传到后端,然后再组合起来,避免大文件直接回源导致多副本和多次回源的问题。

3.4 http_secure_link_module

前面说到的防盗链可以用这个来做,但是这个一般是针对那种文件下载时候用到的,比如从网页下载时候,服务端生成一个加密URL给用户,然后这个URL有过期时间之类的,避免此URL被多次分享出去,不过普通的素材加载还是用普通的防盗链即可。

3.5 http_sub_module

替换响应给用户的内容,相对于sed之后再返回,比如可以在需要临时全局修改网站背景或者title时候可以一次性处理好。

4. 扩展项目

简单介绍下大名鼎鼎的两个基于nginx的扩展项目,也是我们线上有很多地方用到的。

4.1 openresty

集成lua脚本,几乎可以完成任何普通web相关的需求。

比如URL加密进行防劫持和防盗链,服务端动态生成一串aes加密的URL给CDN,CDN的openresty解密之后用普通的URL转发到后端,然后再返回给用户正确的内容。

4.2 tengine

淘宝的nginx修改版,实现了很多nginx的收费功能或者是特殊功能,比如动态加载、concat合并请求,动态解析等。

我们python开发的后台基本都是用的这个版本,主要是利用了concat的合并素材的功能。

5. 结语

Nginx是个非常实用软件,部分功能已经超越了普通的web服务定位,同时它具备开源、轻量、自动化等特性,能有效解决实际工作中很多特殊场景的需求。

那些实用的Nginx规则的更多相关文章

  1. nginx规则总结

    location正则写法 一个示例: location = / { # 精确匹配 / ,主机名后面不能带任何字符串 [ configuration A ] } location / { # 因为所有的 ...

  2. nginx规则和ci的支持

    CI框架下nginx重写规则,不再404 http://blog.csdn.net/EI__Nino/article/details/8599304 server { listen 80; serve ...

  3. Nginx 使用 sever 段规则屏蔽恶意 User Agent

    相对于 Apache,Nginx 占用的系统资源更少,更适合 VPS 使用.恶意的 User Agent 无处不在,博客更换到 WordPress 没几天,就被 SPAM(垃圾留言)盯上,又被暴力破解 ...

  4. 实例讲解Nginx下的rewrite规则

    一.正则表达式匹配,其中:* ~ 为区分大小写匹配* ~* 为不区分大小写匹配* !~和!~*分别为区分大小写不匹配及不区分大小写不匹配二.文件及目录匹配,其中:* -f和!-f用来判断是否存在文件* ...

  5. Nginx的Rewrite规则与实例

    通过Rewrite规则可以实现规范的URL.根据变量来做URL转向及选择配置,用好Rewrite有时起到事半功倍的效果. 语法 Nginx的Rewrite相比Apache的要好理解很多,主要使用指令有 ...

  6. nginx 正则及rewrite常用规则实例

    一.正则表达式匹配,其中:* ~ 为区分大小写匹配* ~* 为不区分大小写匹配* !~和!~*分别为区分大小写不匹配及不区分大小写不匹配二.文件及目录匹配,其中:* -f和!-f用来判断是否存在文件* ...

  7. 实例讲解Nginx下的rewrite规则(转)

    一.正则表达式匹配,其中:* ~ 为区分大小写匹配* ~* 为不区分大小写匹配* !~和!~*分别为区分大小写不匹配及不区分大小写不匹配二.文件及目录匹配,其中:* -f和!-f用来判断是否存在文件* ...

  8. nginx rewrite规则实例讲解

    一.正则表达式匹配,其中: * ~ 为区分大小写匹配* ~* 为不区分大小写匹配* !~和!~*分别为区分大小写不匹配及不区分大小写不匹配 二.文件及目录匹配,其中:* -f和!-f用来判断是否存在文 ...

  9. nginx 域名跳转 Nginx跳转自动到带www域名规则配置、nginx多域名向主域名跳转

    nginx 域名跳转 Nginx跳转自动到www域名规则配置,如果设置使 mgcrazy.com域名在用户访问的时候自动跳转到 www.mgcrazy.com呢?在网上找了好多资料都没有一个完整能解决 ...

随机推荐

  1. 解决:对COM 组件的调用返回了错误 HRESULT E_FAIL

    调用SHDOCVW(web浏览器) COM组件的时候,返回了错误 HRESULT E_FAIL.总结如下: 1. 在控制面板--->管理工具--->服务 中,开启Distributed T ...

  2. 52. N-Queens II(数个数)

    The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens ...

  3. dubbo熔断,限流,服务降级

    1 写在前面 1.1 名词解释 consumer表示服务调用方 provider标示服务提供方,dubbo里面一般就这么讲. 下面的A调用B服务,一般是泛指调用B服务里面的一个接口. 1.2 拓扑图 ...

  4. python 中使用ConfigParser类修改配置文件

    配置文件的格式: [user] user_ip=127.0.0.1 user_name=testuser user_id=13 import ConfigParser conf = ConfigPar ...

  5. IBM究竟是一家怎样的公司

    每次被问到这样的“简单”问题,我都很纠结: 这家公司,从创始至今已经积累了几十万种技术(2015年蝉联专利排行榜23年之久,仅2015年专利数7355项),开发了上万种产品(从银行的交易系统,到航空的 ...

  6. qml学习笔记(二):可视化元素基类Item详解(上半场anchors等等)

    原博主博客地址:http://blog.csdn.net/qq21497936本文章博客地址:http://blog.csdn.net/qq21497936/article/details/78516 ...

  7. Stitching模块中focalsFromHomography初步研究

    在Stitching模块中,通过“光束法平差”的时候,有一个步骤为“通过单应矩阵估算摄像头焦距”,调用的地方为:   , ));    ] ];    d2 ] ]) ] ]);    v1 ] ]  ...

  8. 再也不学AJAX了!(三)跨域获取资源 ③ - WebSocket & postMessage

    让我们先简单回顾一下之前谈到的内容,AJAX是一种无页面刷新的获取服务器资源的混合技术.而基于浏览器的"同源策略",不同"域"之间不可以发送AJAX请求.但是在 ...

  9. SDN前瞻 软件定义网络的一些概念

    SDN的核心:可编程性 SDN的思想:SOA面向服务 面向服务的体系结构(service-oriented architecture SOA) 使网络连接的大量计算机易于合作,以 服务 而不是人工交互 ...

  10. git status出现 fatal: Not a git repository (or any of the parent directories): .git

    fatal: Not a git repository (or any of the parent directories): .git 提示说没有.git这样一个目录,解决办法如下: git ini ...