nginx配置使用笔记:三

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了nginx配置使用笔记:三相关的知识,希望对你有一定的参考价值。

什么是remote_addr

remote_addr代表客户端的IP,但它的值不是由客户端提供的,而是服务端根据客户端的ip指定的,当你

的浏览器访问某个网站时,假设中间没有任何代理,那么网站的web服务器(nginx,Apache等)就会把

remote_addr设为你的机器IP,如果你用了某个代理,那么你的浏览器会先访问这个代理,然后再由这个

代理转发到网站,这样web服务器就会把remote_addr设为这台代理机器的IP。

什么是x_forwarded_for

正如上面所述,当你使用了代理时,web服务器就不知道你的真实IP了,为了避免这个情况,代理服务器通

常会增加一个叫做x_forwarded_for的头信息,把连接它的客户端IP(即你的上网机器IP)加到这个头信息

里,这样就能保证网站的web服务器能获取到真实IP

注释:客户端的IP地址作为键。注意,这里使用的是$binary_remote_addr变量,而不是$remote_addr变量。$remote_addr变量的长度为7字节到15字节,而存储状态在32位平台中占用32字节或64字节,在64位平台中占用64字节。$binary_remote_addr变量的长度是固定的4字节,存储状态在32位平台中占用32字节或64字节,在64位平台中占用64字节。1M共享空间可以保存3.2万个32位的状态,1.6万个64位的状态。如果共享内存空间被耗尽,服务器将会对后续所有的请求返回 503 (Service Temporarily Unavailable) 错误。limit_zone 指令和limit_conn_zone指令同等意思,已经被弃用,就不再做说明了。




 geo:   定义从指定的变量获取客户端的IP地址。默认情况下,nginx从$remote_addr变量取得客户端IP地址,但也可以从其他变量获得(0.7.27版),如果该变量的值不能代表一个合法的IP地址,那么nginx将使用地址“255.255.255.255”。比如:

delete

删除指定网络(0.7.23版)。

default

如果客户端地址不能匹配任意一个定义的地址,nginx将使用此值。 如果使用CIDR,可以用“0.0.0.0/0”代替default。

include

包含一个定义地址和值的文件。可以多次包含。

proxy

定义可信地址(0.8.7,0.7.63版)。 如果请求来自可信地址,nginx将使用其“X-Forwarded-For”头来获得地址。 相对于普通地址,可信地址是顺序检测的。



 

map:  在配置的参数中,第一个是要创建新的变量,它的值取决于后面一个或多个源变量。在 map 块里的参数指定了源变量值和结果值的对应关系。源变量值可以使用字符串或者正则表达式 (0.9.6)。


http://tengine.taobao.org/nginx_docs/cn/docs/http/ngx_http_geo_module.html



经过多层CDN之后取得原始用户的IP地址,nginx 配置取得用户的原始地址







线上的配置如下:

 geo $clientRealIp  $white_ip  {  #$white_ip白名单ip

        default 1;  

        127.0.0.1 0;

122.132.49.241 0;

        123.217.40.142 0;

        123.217.40.143 0;

    }


map $http_x_forwarded_for  $clientRealIp {

        ## 没有通过代理,直接用 remote_addr

""$remote_addr;     #remote_addr客户端ip

        ## 用正则匹配,从 x_forwarded_for 中取得用户的原始IP

        ## 例如   X-Forwarded-For: 202.123.123.11, 208.22.22.234, 192.168.2.100,...

        ## 这里第一个 202.123.123.11 是用户的真实 IP,后面其它都是经过的 CDN 服务器

~^(?P<firstAddr>[0-9\.]+),?.*$$firstAddr;

}


## 通过 map 指令,我们为 nginx 创建了一个变量 $clientRealIp ,这个就是 原始用户的真实 IP 地址, 

## 不论用户是直接访问,还是通过一串 CDN 之后的访问,我们都能取得正确的原始IP地址




  map $white_ip $limit {    

        1  $binary_remote_addr;  

        0 "";  

    }  

这里使用的是$binary_remote_addr变量,而不是$remote_addr变量。$remote_addr变量的长度为7字节到15字节,而存储状态在32位平台中占用32字节或64字节,在64位平台中占用64字节。$binary_remote_addr变量的长度是固定的4字节,存储状态在32位平台中占用32字节或64字节,在64位平台中占用64字节。1M共享空间可以保存3.2万个32位的状态,1.6万个64位的状态。如果共享内存空间被耗尽,服务器将会对后续所有的请求返回 503 (Service Temporarily Unavailable) 错误。limit_zone 指令和limit_conn_zone指令同等意思,已经被弃用,就不再做说明了。

  limit_req_zone  $limit zone=tlcy_com:10m rate=50r/s;    #$limit为空不限制   限制平均每秒不超过一个请求50个 

  limit_req_log_level  info;

  limit_conn_zone  $limit zone=addr:10m;

  limit_conn_log_level info;

  

   server

 {

        listen       80;

        server_name xxx;

        location / {

            proxy_next_upstream http_502 http_504 error timeout invalid_header;

            proxy_pass http://xxx;

            index  index.html index.htm index.jsp;

            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;

       proxy_ignore_client_abort on;

                }


   #if ($http_user_agent ~ "M8")

           #{

           #     return 504;

           #}

      if ($request_method !~ ^(GET|HEAD|POST)$ ) {

            return 444;

}


####过滤方法post get

       set $flag 0;

       if ($request_method ~ "POST" ){

       set $flag "${flag}1";

             }

       if ($request_uri ~* "/tlcysns/user/getMsg.action.*$" ) {

       set $flag "${flag}1";

             }

       if ($flag = "011"){

          return 444;

             }



  set $flag 1;

       if ($request_method ~ "GET" ){

       set $flag "${flag}1";

             }

       if ($request_uri ~* "/tlcysns/user/getMsg.action.*$" ) {

       set $flag "${flag}1";

             }

       if ($flag = "111"){

            return 200 ‘{"result":1,"msgs":[],"h_msgs":[]}‘;

             }


#limit_req zone=tlcy_com burst=20 ;     #限制平均每秒不超过一个请求50个,同时允许超过频率限制的请求数不多于20个


#limit_req zone=ttlsa_com burst=5 nodelay;     #如果不希望超过的请求被延迟,可以用nodelay参数。

#limit_conn addr 100; #是限制每个IP只能发起100个连接 (addr 要跟 limit_conn_zone 的变量对应)

#limit_rate 100k; #是对每个连接限速100k。这里是对连接限速,而不是对IP限速!如果一个IP允许两个并发连接,那么这个IP就是限速limit_rate * 2




        if ($http_user_agent ~ "i500")

      {

    return 504;

           }

        access_log /data/logs/nginx/sns_access.log main;

  

}










现在我们面对的最直接的问题就是, 经过这么多层加速,我怎么得到“最前面普通用户的 IP 地址”呢?

(这里只说明结果,不了解 Http 协议的人请自行 Google 或者 Wikipedia  http://zh.wikipedia.org/zh-cn/X-Forwarded-For  )


当一个 CDN 或者透明代理服务器把用户的请求转到后面服务器的时候,这个 CDN 服务器会在 Http 的头中加入 一个记录


X-Forwarded-For :  用户IP, 代理服务器IP


如果中间经历了不止一个 代理服务器,像 www.bzfshop.net 中间建立多层代理之后,这个 记录会是这样


X-Forwarded-For :  用户IP, 代理服务器1-IP, 代理服务器2-IP, 代理服务器3-IP, ….


可以看到经过好多层代理之后, 用户的真实IP 在第一个位置, 后面会跟一串 中间代理服务器的IP地址,从这里取到用户真实的IP地址,针对这个 IP 地址做限制就可以了,


 


2.2 经过多层CDN之后取得原始用户的IP地址,nginx 配置取得用户的原始地址


map $http_x_forwarded_for  $clientRealIp {

        ## 没有通过代理,直接用 remote_addr

""$remote_addr;  

        ## 用正则匹配,从 x_forwarded_for 中取得用户的原始IP

        ## 例如   X-Forwarded-For: 202.123.123.11, 208.22.22.234, 192.168.2.100,...

        ## 这里第一个 202.123.123.11 是用户的真实 IP,后面其它都是经过的 CDN 服务器

~^(?P<firstAddr>[0-9\.]+),?.*$$firstAddr;

}


## 通过 map 指令,我们为 nginx 创建了一个变量 $clientRealIp ,这个就是 原始用户的真实 IP 地址, 

## 不论用户是直接访问,还是通过一串 CDN 之后的访问,我们都能取得正确的原始IP地址




2.3 测试、测试

很多时候,你在网上搜到一堆配置,你照着做了,但是你怎么知道这个配置真的正确 ?是的,我们需要自己做一个有效的真实的测试,验证它是正确的之后才真的采用它


Nginx 这种配置怎么测试呢? 用 Echo 模块,如果你知道 Nginx 这个模块的话。


以 www.bzfshop.net 网站为例, 我们首先测试这个 $clientRealIp 是否真的是我们客户机的 IP 地址,在网站上增加一个访问地址,比如  www.bzfshop.net/nginx-test,配置如下:


给 Nginx 增加一个测试地址Shell


server {

listen   80;

        server_name  www.bzfshop.net;


        ## 当用户访问 /nginx-test 的时候,我们输出 $clientRealIp 变量,看看这个变量

        ## 值是不是真的 用户源IP 地址

        location /nginx-test {

                echo $clientRealIp;

        }

}


server {

    listen   80;

        server_name  www.bzfshop.net;

 

        ## 当用户访问 /nginx-test 的时候,我们输出 $clientRealIp 变量,看看这个变量

        ## 值是不是真的 用户源IP 地址

        location /nginx-test {

                echo $clientRealIp;

        }

}

接下来,用你的浏览器访问  www.bzfshop.net/nginx-test,这个时候会弹出框下载一个文件 nginx-test,下载完成用 notepad++ 打开,里面就是一个 IP 地址


访问 www.ip138.com ,看看这个里面记录的IP地址是否和 ip138 侦测的IP 一致?


通过这种方式,你就可以对 Nginx 的一些复杂配置做有效的测试。


经过测试,我们确认 通过多层CDN 之后,$clientRealIp 仍然是有效的原始用户IP地址


 


 2.4 根据用户的真实 IP 做连接限制

下面是修改之后的 Nginx 配置:


CDN环境下 Nginx 的安全配置Shell


## 这里取得原始用户的IP地址

map $http_x_forwarded_for  $clientRealIp {

""$remote_addr;

~^(?P<firstAddr>[0-9\.]+),?.*$$firstAddr;

}


## 针对原始用户 IP 地址做限制

limit_conn_zone $clientRealIp zone=TotalConnLimitZone:20m ;

limit_conn  TotalConnLimitZone  50;

limit_conn_log_level notice;


## 针对原始用户 IP 地址做限制

limit_req_zone $clientRealIp zone=ConnLimitZone:20m  rate=10r/s;

#limit_req zone=ConnLimitZone burst=10 nodelay;

limit_req_log_level notice;


## 具体服务器配置

server {

listen   80;

location ~ \.php$ {

                ## 最多 5 个排队, 由于每秒处理 10 个请求 + 5个排队,你一秒最多发送 15 个请求过来,再多就直接返回 503 错误给你了

limit_req zone=ConnLimitZone burst=5 nodelay;


fastcgi_pass   127.0.0.1:9000;

fastcgi_index  index.php;

includefastcgi_params;

}


}


## 这里取得原始用户的IP地址

map $http_x_forwarded_for  $clientRealIp {

    ""    $remote_addr;

    ~^(?P<firstAddr>[0-9\.]+),?.*$    $firstAddr;

}

 

## 针对原始用户 IP 地址做限制

limit_conn_zone $clientRealIp zone=TotalConnLimitZone:20m ;

limit_conn  TotalConnLimitZone  50;

limit_conn_log_level notice;

 

## 针对原始用户 IP 地址做限制

limit_req_zone $clientRealIp zone=ConnLimitZone:20m  rate=10r/s;

#limit_req zone=ConnLimitZone burst=10 nodelay;

limit_req_log_level notice;

 

## 具体服务器配置

server {

    listen   80;

    location ~ \.php$ {

                ## 最多 5 个排队, 由于每秒处理 10 个请求 + 5个排队,你一秒最多发送 15 个请求过来,再多就直接返回 503 错误给你了

        limit_req zone=ConnLimitZone burst=5 nodelay;

 

        fastcgi_pass   127.0.0.1:9000;

        fastcgi_index  index.php;

        include    fastcgi_params;

    }    

 

}

 


后记:

通过上面的配置,现在你的网站可以完美的配合任何 网络加速服务(CDN)的使用,并且同时能保证对“最终用户的限制”。


写这篇文章的原因是因为 我们最近把 www.bzfshop.net 迁移到  360网站卫士(wangzhan.360.cn)  上了,使用 360网站卫士 做我们的加速服务器和安全保护,同时我们网站自身 nginx 本身也配置了防止攻击的安全措施, 结果我们的安全配置把  360网站卫士的加速服务器给 盾 掉了,因为所有用户的访问都通过加速服务器过来,很明显加速服务器超过了我们的“连接限制”。经过上面的改造之后,现在我们的 Nginx 安全配置能够和 360加速服务器 完美配合,同时能对终端的用户访问作限制。


写下这些文字,希望对看到这篇文章的朋友会有用。


Nginx 有 2 个模块用于控制访问“数量”和“速度”,简单的说,控制你最多同时有 多少个访问,并且控制你每秒钟最多访问多少次, 你的同时并发访问不能太多,也不能太快,不然就“杀无赦”。


HttpLimitZoneModule    限制同时并发访问的数量


HttpLimitReqModule     限制访问数据,每秒内最多几个请求


limit_conn_zone语法: limit_conn_zone $variable zone=name:size;默认值: none配置段: http该指令描述会话状态存储区域。键的状态中保存了当前连接数,键的值可以是特定变量的任何非空值(空值将不会被考虑)。$variable定义键,zone=name定义区域名称,后面的limit_conn指令会用到的。size定义各个键共享内存空间大小。如:

limit_conn_zone $binary_remote_addr zone=addr:10m;


注释:客户端的IP地址作为键。注意,这里使用的是$binary_remote_addr变量,而不是$remote_addr变量。$remote_addr变量的长度为7字节到15字节,而存储状态在32位平台中占用32字节或64字节,在64位平台中占用64字节。$binary_remote_addr变量的长度是固定的4字节,存储状态在32位平台中占用32字节或64字节,在64位平台中占用64字节。1M共享空间可以保存3.2万个32位的状态,1.6万个64位的状态。如果共享内存空间被耗尽,服务器将会对后续所有的请求返回 503 (Service Temporarily Unavailable) 错误。limit_zone 指令和limit_conn_zone指令同等意思,已经被弃用,就不再做说明了。


limit_conn_log_level语法:limit_conn_log_level info | notice | warn | error默认值:error配置段:http, server, location当达到最大限制连接数后,记录日志的等级。


limit_conn语法:limit_conn zone_name number默认值:none配置段:http, server, location指定每个给定键值的最大同时连接数,当超过这个数字时被返回503 (Service Temporarily Unavailable)错误。如:



limit_conn_zone $binary_remote_addr zone=addr:10m;

server {

    location /www.2cto.com/ {

        limit_conn addr 1;

    }

}


同一IP同一时间只允许有一个连接。当多个 limit_conn 指令被配置时,所有的连接数限制都会生效。比如,下面配置不仅会限制单一IP来源的连接数,同时也会限制单一虚拟服务器的总连接数:




limit_conn_zone $binary_remote_addr zone=perip:10m;

limit_conn_zone $server_name zone=perserver:10m;

server {

    limit_conn perip 10;

    limit_conn perserver 100;

}


[warning]limit_conn指令可以从上级继承下来。

limit_conn_status语法: limit_conn_status code;默认值: limit_conn_status 503;配置段: http, server, location该指定在1.3.15版本引入的。指定当超过限制时,返回的状态码。默认是503。


limit_rate语法:limit_rate rate默认值:0配置段:http, server, location, if in location对每个连接的速率限制。参数rate的单位是字节/秒,设置为0将关闭限速。 按连接限速而不是按IP限制,因此如果某个客户端同时开启了两个连接,那么客户端的整体速率是这条指令设置值的2倍。


limit_req_zone语法: limit_req_zone $variable zone=name:size rate=rate;默认值: none配置段: http设置一块共享内存限制域用来保存键值的状态参数。 特别是保存了当前超出请求的数量。 键的值就是指定的变量(空值不会被计算)。如

limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;


说明:区域名称为one,大小为10m,平均处理的请求频率不能超过每秒一次。键值是客户端IP。使用$binary_remote_addr变量, 可以将每条状态记录的大小减少到64个字节,这样1M的内存可以保存大约1万6千个64字节的记录。如果限制域的存储空间耗尽了,对于后续所有请求,服务器都会返回 503 (Service Temporarily Unavailable)错误。速度可以设置为每秒处理请求数和每分钟处理请求数,其值必须是整数,所以如果你需要指定每秒处理少于1个的请求,2秒处理一个请求,可以使用 “30r/m”。


limit_req_log_level语法: limit_req_log_level info | notice | warn | error;默认值: limit_req_log_level error;配置段: http, server, location设置你所希望的日志级别,当服务器因为频率过高拒绝或者延迟处理请求时可以记下相应级别的日志。 延迟记录的日志级别比拒绝的低一个级别;比如, 如果设置“limit_req_log_level notice”, 延迟的日志就是info级别。


limit_req_status语法: limit_req_status code;默认值: limit_req_status 503;配置段: http, server, location该指令在1.3.15版本引入。设置拒绝请求的响应状态码。


limit_req语法: limit_req zone=name [burst=number] [nodelay];默认值: —配置段: http, server, location设置对应的共享内存限制域和允许被处理的最大请求数阈值。 如果请求的频率超过了限制域配置的值,请求处理会被延迟,所以所有的请求都是以定义的频率被处理的。 超过频率限制的请求会被延迟,直到被延迟的请求数超过了定义的阈值,这时,这个请求会被终止,并返回503 (Service Temporarily Unavailable) 错误。这个阈值的默认值为0。如:


limit_req_zone $binary_remote_addr zone=limit_com:10m rate=1r/s;

server {

    location /www.2cto.com/ {

        limit_req zone=limit_com burst=5;

    }

}


限制平均每秒不超过一个请求,同时允许超过频率限制的请求数不多于5个。如果不希望超过的请求被延迟,可以用nodelay参数,如:


limit_req zone=ttlsa_com burst=5 nodelay;

--------完成配置事例--------------------------------------------


## 用户的 IP 地址 $limit 作为 Key,每个 IP 地址最多有 50 个并发连接


## 你想开 几千个连接 刷死我? 超过 50 个连接,直接返回 503 错误给你,根本不处理你的请求了


当,然这是都是ngin来处理,不会影响后端的tomcat等WEB 应用 ,如果nginx网卡流量堵塞和单台压力问题就的想别的办法了。后面会说在解决的

  limit_req_zone  $limit zone=tlcy_com:10m rate=10r/s;  limit_req_log_level  info;  limit_conn_zone  $limit zone=addr:10m;  limit_conn_log_level info;


## 用户的 IP 地址 $limit 作为 Key,每个 IP 地址每秒处理 10 个请求


## 你想用程序每秒几百次的刷我,没戏,再快了就不处理了,直接返回 503 错误给你

## 具体服务器配置

 


http{....

  

   limit_req_zone  $limit zone=tlcy_com:10m rate=10r/s;

  limit_req_log_level  info;

  limit_conn_zone  $limit zone=addr:10m;

  limit_conn_log_level info;

  server

  {

    listen      80;

    server_name  www.2cto.com;

  

  

  if ($http_user_agent ~* LWP::Simple|BBBike|wget|Sosospider|YodaoBot) {

   return 403;

  }

  

##    root  /data/www/;

##    index  hou.txt;

   location /mp4/

    {

    if ($request_method !~ ^(GET|HEAD|POST)$ ) {

            return 444;

   }

                    }

    location / {

  

    if ($request_method !~ ^(GET|HEAD)$ ) {

            return 444;

        }

  

            proxy_next_upstream http_502 http_504 error timeout invalid_header;

            proxy_pass http://tlcy;

            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 all;

                }


## 最多 5 个排队, 由于每秒处理 10 个请求 + 5个排队,你一秒最多发送 15 个请求过来,

再多就直接返回 503 错误给你了           

  


limit_req zone=tlcy_com burst=5  nodelay;

  limit_conn addr 10;

 

    location ~* \.(gif|jpg|png|swf|flv)$ {

    valid_referers none blocked www.2cto.com ;

    if ($invalid_referer) {

    rewrite ^/ http://www.2cto.com/403.html;

  #return 404;

 }

  }

  }


事务都具有两面性的。ngx_http_limit_conn_module 模块虽说可以解决当前面临的并发问题,但是会引入另外一些问题的。如前端如果有做LVS或反代,而我们后端启用了该模块功能,那不是非常多503错误了? 这样的话,可以在前端启用该模块,要么就是设置白名单。

------------------------------白名单设置-----------------------------------------


## 具体服务器配置

http{....

  geo $white_ip  {

        default 1;

        127.0.0.1 0;

        10.0.0.0/8 0;

    }

#白名单

  

  map $white_ip $limit {

        1  $binary_remote_addr;

        0 "";

    }

     

  limit_req_zone  $limit zone=tlcy_com:10m rate=10r/s;

  limit_req_log_level  info;

  limit_conn_zone  $limit zone=addr:10m;

  limit_conn_log_level info;

  server

  {

    listen      80;

    server_name  www.hzcsky.com;

  

  

  if ($http_user_agent ~* LWP::Simple|BBBike|wget|Sosospider|YodaoBot) {

   return 403;

  }

  

##    root  /data/www/;

##    index  hou.txt;

 

 

   location /mp4/

    {

    if ($request_method !~ ^(GET|HEAD|POST)$ ) {

            return 444;

   }

                    }

    location / {

  

    if ($request_method !~ ^(GET|HEAD)$ ) {

            return 444;

        }

  

            proxy_next_upstream http_502 http_504 error timeout invalid_header;

            proxy_pass http://tlcy;

            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 all;

                }


## 最多 5 个排队, 由于每秒处理 10 个请求 + 5个排队,你一秒最多发送 15 个请求过来,

再多就直接返回 503 错误给你了           

  


limit_req zone=tlcy_com burst=5  nodelay;

  limit_conn addr 10;

 

    location ~* \.(gif|jpg|png|swf|flv)$ {

    valid_referers none blocked www.2cto.com ;

    if ($invalid_referer) {

    rewrite ^/ http://www.2cto.com/403.html;

  #return 404;

 }

  }

  }


 #################如果 单台nginx解决不了前面需要LVS或者haproxy 了做4层 然后nginx多个 来解决这个问题,如果多台的 因为过来的全是LVS 的IP 这需要很麻烦的解决了。


(这里只说明结果,不了解 Http 协议的人请自行 Google 或者 Wikipedia  http://zh.wikipedia.org/zh-cn/X-Forwarded-For  )


当一个 CDN 或者透明代理服务器把用户的请求转到后面服务器的时候,这个 CDN 服务器会在 Http 的头中加入 一个记录

X-Forwarded-For :  用户IP, 代理服务器IP


如果中间经历了不止一个 代理服务器,像 www.bzfshop.net 中间建立多层代理之后,这个 记录会是这样

X-Forwarded-For :  用户IP, 代理服务器1-IP, 代理服务器2-IP, 代理服务器3-IP, ….


可以看到经过好多层代理之后, 用户的真实IP 在第一个位置, 后面会跟一串 中间代理服务器的IP地址,从这里取到用户真实的IP地址,针对这个 IP 地址做限制就可以了,

 

nginx 配置


取得用户的原始地址


日志开启显示 :

    log_format main ‘$http_x_forwarded_for $remote_addr - - $time_iso8601 "$request_method $scheme://$host$request_uri $server_protocol" $status $bytes_sent "$http_referer" "$http_user_agent" $request_time $upstream_cache_status:TCP‘;

map $http_x_forwarded_for  $clientRealIp {

        ## 没有通过代理,直接用 remote_addr

    ""    $remote_addr; 

        ## 用正则匹配,从 x_forwarded_for 中取得用户的原始IP

        ## 例如   X-Forwarded-For: 202.123.123.11, 208.22.22.234, 192.168.2.100,...

        ## 这里第一个 202.123.123.11 是用户的真实 IP,后面其它都是经过的 CDN 服务器

    ~^(?PfirstAddr>[0-9\.]+),?.*$    $firstAddr;

}

 

## 通过 map 指令,我们为 nginx 创建了一个变量 $clientRealIp ,这个就是 原始用户的真实 IP 地址,

## 不论用户是直接访问,还是通过一串 CDN 之后的访问,我们都能取得正确的原始IP地址

 

完整配置事例:


## 具体服务器配置

http{

  

   map $http_x_forwarded_for  $limit {

    ""    $remote_addr;

    ~^(?P[0-9\.]+),?.*$    $firstAddr;

   }

  

  

#  map $white_ip $limit { 

 #       1  $clientRealIp; 

 #       0 ""; 

 #   } 

  

  limit_req_zone  $limit zone=tlcy_com:10m rate=5r/s;

  limit_req_log_level  info;

  limit_conn_zone  $limit zone=addr:10m;

  limit_conn_log_level info;

  

  server

  {

    listen      80;

 

 

    server_name  www.2cto.com;

  

  

  if ($http_user_agent ~* LWP::Simple|BBBike|wget|Sosospider|YodaoBot) {

   return 403;

  }

  

##    root  /data/www/;

##    index  hou.txt;

   location /mp4/

    {

    if ($request_method !~ ^(GET|HEAD|POST)$ ) {

            return 444;

   }

                    }

    location / {

  

    if ($request_method !~ ^(GET|HEAD)$ ) {

            return 444;

        }

  

            proxy_next_upstream http_502 http_504 error timeout invalid_header;

            proxy_pass http://tlcy;

            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 all;

                }

## 最多 5 个排队, 由于每秒处理 10 个请求 + 5个排队,你一秒最多发送 15 个请求过来,

再多就直接返回 503 错误给你了           

   limit_req zone=tlcy_com burst=5  nodelay;

   limit_conn addr 10;

  

     location ~* \.(gif|jpg|png|swf|flv)$ {

     valid_referers none blocked www.2cto.com ;

     if ($invalid_referer) {

     rewrite ^/ http://www.2cto.com/403.html;

   #return 404;

  }

   }

   }


 因为他限制的是 原始IP 不用设置白名单之类了就。自己人可以直接访问nginx层,是原始IP地址没有限制就。


还要合理的封掉IP 就需要日志配合脚本了:

#!/bin/bash

#取得参数$1为并发阈值,若留空则默认允许单IP最大200并发!


if [[ -z $1 ]];then

        num=200

else

        num=$1

fi

  

LOG=/root/log/nginx/sns_access.log

STATUS=503

#请求检查、判断及拉黑主功能函数

function check(){

     iplist=`cat  $LOG  |grep  -i $STATUS |grep -i ","  |awk  ‘{print $2}‘ |grep -v "-" |sed "s#,##g" |sort |uniq -cd  |sort -rn| awk -v  str=$num ‘{if ($1>str){print $2}}‘`

        if [[ ! -z $iplist ]];

                then

                >/data/shell/black_ip.txt

                for black_ip in $iplist

                do

                        #白名单过滤中已取消IP段的判断功能,可根据需要自行修改以下代码

                        #exclude_ip=`echo $black_ip | awk -F"." ‘{print $1"."$2"."$3}‘`

                        #grep -q $exclude_ip ./white_ip.txt

                        grep -q $black_ip /data/shell/white_ip.txt

                        if [[ $? -eq 0 ]];then

                                echo "$black_ip (white_ip)" >>/data/shell/black_ip.txt

                        else

 

 

                                echo $black_ip >> /data/shell/black_ip.txt    

                               # iptables -nL | grep $black_ip ||(iptables -I INPUT -s $black_ip -j DROP & echo "$black_ip  `date +%Y-%m-%H:%M:%S`">>/data/shell/denylog.txt )

                        fi

                done

                #存在并发超过阈值的单IP就发送邮件

              #  if [[ `cat ./sendmail` == 1 ]];then sendmsg;fi

        fi

}

  

function checka(){

        iplist=`cat  $LOG  |grep  -i $STATUS |grep -v "," |awk  ‘{print $1}‘ |sort  |uniq -cd   |sort  -rn | awk -v  str=$num ‘{if ($1>str){print $2}}‘`

        if [[ ! -z $iplist ]];

                then

                >/data/shell/black_ip.txt

                for black_ip in $iplist

                do

                        #白名单过滤中已取消IP段的判断功能,可根据需要自行修改以下代码

                        #exclude_ip=`echo $black_ip | awk -F"." ‘{print $1"."$2"."$3}‘`

                        #grep -q $exclude_ip ./white_ip.txt

                        grep -q $black_ip /data/shell/white_ip.txt

                        if [[ $? -eq 0 ]];then

                                echo "$black_ip (white_ip)" >>/data/shell/black_ip.txt

                        else

                                echo $black_ip >> /data/shell/black_ip.txt

                               # iptables -nL | grep $black_ip ||(iptables -I INPUT -s $black_ip -j DROP & echo "$black_ip  `date +%Y-%m-%H:%M:%S`">>/data/shell

#/denylog.txt )

                        fi

                done

                #存在并发超过阈值的单IP就发送邮件

              #  if [[ `cat ./sendmail` == 1 ]];then sendmsg;fi

        fi

}

#发邮件函数

function sendmsg(){

        netstat -nutlp | grep "sendmail" >/dev/null 2>&1 || /etc/init.d/sendmail start >/dev/null 2>&1

        echo -e "From: 发邮件地@qq.com\nTo:收邮件地@qq.com\nSubject:Someone Attacking your system!!\nIts Ip is" >./message

        cat ./black_ip.txt >>./message

        /usr/sbin/sendmail -f 发邮件地@qq.com -t 收邮件地@qq.com -i /message

 

 

        >./sendmail

}

  

##间隔10s无限循环检查函数

#while true

#do

#        check

#        #每隔10s检查一次,时间可根据需要自定义

#        sleep 10

#done

#

check #处理没有代理的IP


checka #处理多层的IP

我们日志是5分钟切割一次。所以就检查5分钟内非法的IP 给封掉,在写个2小时重置IPtables的计划任务 就行了。







设置两个域名

    server {

        listen       80;

        server_name  test1.magedu.com;

        root         /test1/;

        }

        location /status{

                stub_status on;

        }

        location /req-status {

                req_status_show on;

        }

    }

    server {

        listen       80;

        server_name  test2.magedu.com;

        root         /test2/;

        location / {

                 index  index.html index.htm;

        }

    }

代理设置

upstream backend {

server backend1.example.com weight=5;

server 127.0.0.1:8080       max_fails=3 fail_timeout=30s;

server unix:/tmp/backend3;


server backup1.example.com  backup;

}

max_fails=3一共做三次健康状态检测fail_timeout=30s每30秒做一个健康状态检测    三次都失败就标记为不可用

格式:server address [parameters];可以是ip:port   hostname   unix套接字(本地通信)



        listen       80;

        server_name sns.audiocn.org;

        location / {

            proxy_next_upstream http_502 http_504 error timeout invalid_header;#指定在何种情况下一个失败的请求应该被发送到下一台后端服务器:

            proxy_pass http://tlcysns;

            index  index.html index.htm index.jsp;

            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;

   proxy_ignore_client_abort on;

                }

设置后端服务器“Location”响应头和“Refresh”响应头的替换文本。 假设后端服务器返回的响应头是 “Location: http://localhost:8000/two/some/uri/”,那么指令

proxy_redirect http://localhost:8000/two/ http://frontend/one/;

将把字符串改写为 “Location: http://frontend/one/some/uri/”。



NGINX的proxy_redirect功能比较强大,其作用是对发送给客户端的URL进行修改。以例子说明: 


   server { 

       listen       80; 

       server_name  test.abc.com; 

       location / { 

            proxy_pass http://10.10.10.1:9080; 

       } 

   }这段配置一般情况下都正常,但偶尔会出错, 错误在什么地方呢? 抓包发现服务器给客户端的跳转指令里加了端口号,如 Location: http://test.abc.com:9080/abc.html 。因为nginx服务器侦听的是80端口,所以这样的URL给了客户端,必然会出错.针对这种情况, 加一条proxy_redirect指令: proxy_redirect http://test.abc.com:9080/ / ,把所有“http://test.abc.com:9080/”的内容替换成“/”再发给客户端,就解决了。 


   server { 

       listen       80; 

       server_name  test.abc.com; 

       proxy_redirect http://test.abc.com:9080/ /; 

       location / { 

            proxy_pass http://10.10.10.1:9080; 

       } 

   } 


本文出自 “16期松鼠&青蛙” 博客,请务必保留此出处http://tlinux.blog.51cto.com/7288656/1746281

以上是关于nginx配置使用笔记:三的主要内容,如果未能解决你的问题,请参考以下文章

Nginx学习笔记05错误页面重定向

关于Nginx 用户认证SSL证书生成配置的一些笔记

关于Nginx 用户认证SSL证书生成配置的一些笔记

python3 + Django + uwsgi + nginx 配置部署笔记

linux学习笔记——搭建基于nginx的web服务器多核配置nginx配置参数

linux自学笔记--nginx基本配置