Category Archives: Web Server

web服务器相关,包括nginx,apache,php,php-fpm,mysql等一些优化,以及centos,ubuntu,Freebsd等linux和unux服务器知识。

NGINX多层转发或使用CDN之后如何获取用户真实IP

##1.背景知识

1.1. 前提知识点:

关键词:ngx_http_realip_moduleHAProxy反向代理出口IP

还有nginx中的几个变量:

  • remote_addr

    代表客户端的IP,但它的值不是由客户端提供的,而是服务端根据客户端的ip指定的,当你的浏览器访问某个网站时,假设中间没有任何代理,那么网站的web服务器(Nginx,Apache等)就会把remote_addr设为你的机器IP,如果你用了某个代理,那么你的浏览器会先访问这个代理,然后再由这个代理转发到网站,这样web服务器就会把remote_addr设为这台代理机器的IP,除非代理将你的IP附在请求header中一起转交给web服务器。

  • X-Forwarded-For(简称XFF)

    X-Forwarded-For 是一个 HTTP 扩展头部。HTTP/1.1(RFC 2616)协议并没有对它的定义,它最开始是由 Squid 这个缓存代理软件引入,用来表示 HTTP 请求端真实 IP。如今它已经成为事实上的标准,被各大 HTTP 代理、负载均衡等转发服务广泛使用,并被写入 RFC 7239(Forwarded HTTP Extension)标准之中。

    XFF的格式为:

    X-Forwarded-For: client, proxy1, proxy2
    

    XFF 的内容由「英文逗号 + 空格」隔开的多个部分组成,最开始的是离服务端最远的设备 IP,然后是每一级代理设备的 IP。(注意:如果未经严格处理,可以被伪造

    如果一个 HTTP 请求到达服务器之前,经过了三个代理 Proxy1、Proxy2、Proxy3,IP 分别为 IP1、IP2、IP3,用户真实 IP 为 IP0,那么按照 XFF 标准,服务端最终会收到以下信息:

    X-Forwarded-For: IP0, IP1, IP2
    

    Proxy3 直连服务器,它会给 XFF 追加 IP2,表示它是在帮 Proxy2 转发请求。列表中并没有 IP3,IP3 可以在服务端通过 Remote Address 字段获得。我们知道 HTTP 连接基于 TCP 连接,HTTP 协议中没有 IP 的概念,Remote Address 来自 TCP 连接,表示与服务端建立 TCP 连接的设备 IP,在这个例子里就是 IP3。Remote Address 无法伪造,因为建立 TCP 连接需要三次握手,如果伪造了源 IP,无法建立 TCP 连接,更不会有后面的 HTTP 请求。但是在正常情况下,web服务器获取Remote Address只会获取到上一级的IP,本例里则是proxy3 的 IP3,这里先埋个伏笔

  • X-Real-IP

    这又是一个自定义头部字段,通常被 HTTP 代理用来表示与它产生 TCP 连接的设备 IP,这个设备可能是其他代理,也可能是真正的请求端,这个要看经过代理的层级次数或是是否始终将真实IP一路传下来。(注意:如果未经严格处理,可以被伪造

1.2.前提与铁律

铁律:当多层代理或使用CDN时,如果代理服务器不把用户的真实IP传递下去,那么业务服务器将永远不可能获取到用户的真实IP。

1.3.用户真实IP的来源和现实情况

首先说用户真实的IP也会存在很多人共用一个IP的情况。用户的请求到达业务服务器会经过以下几种情形:

####1.3.1.宽带供应商提供独立IP

比如家里电信宽带上网,电信给分配了公网ip,那么一个请求经过的ip路径如下:

192.168.0.101(用户电脑ip)–>192.168.0.1/116.1.2.3(路由器的局域网ip及路由器得到的电信公网ip)–>119.147.19.234(业务的前端负载均衡服务器)–>192.168.126.127(业务处理服务器)。

这种情况下,119.147.19.234会把得到的116.1.2.3附加到头信息中传给192.168.126.127,因此这种情况下,我们取得的用户ip则为:116.1.2.3。如果119.147.19.234没有把116.1.2.3附加到头信息中传给业务服务器,业务服务器就只能取上上一级的119.147.19.234的内网IP.

1.3.2.宽带供应商不能提供独立IP

宽带提供商没有足够的公网ip,分配的是个内网ip,比如长宽等小的isp。请求路径则可能为:

192.168.0.123(用户电脑ip)–>192.168.0.1/10.0.1.2(路由器的局域网ip及路由器得到的运营商内网ip)–>211.162.78.1(网络运营商长城宽带的公网ip)–>119.147.19.234(业务的前端负载均衡服务器)–>192.168.126.127(业务处理服务器)。
这种情况下得到的用户ip,就是211.162.78.1。 这种情况下,就可能出现一个ip对应有数十上百个用户的情况了(受运营商提供的代理规模决定,比如可能同时有几千或上万的宽带用户都是从211.162.78.1这个ip对外请求)。

####1.3.3.手机2g上网
网络提供商没法直接提供ip给单个用户终端,以中国移动cmwap上网为例,因此请求路径可能为:

手机(手机上没法查看到ip)–> 10.0.0.172(cmwap代理服务器ip)–>10.0.1.2(移动运营商内网ip)–>202.96.75.1(移动运营商的公网ip)–>119.147.19.234(业务的前端负载均衡服务器)–>192.168.126.127(业务处理服务器)。
这种情况下得到的用户ip,就是202.96.75.1。2008年的时候整个广东联通就三个手机上网的公网ip,因此这种情况下,同一ip出现数十万用户也是正常的。

####1.3.4.大厂,有几万或数十万员工,但是出口上网ip就一个
这种也会出现来自同一ip的超多用户,比如腾讯、百度等某一个办公区,可能达到几万人,但出口IP可能就那么几个。

2.如何获取用户真实IP

2.1. 当业务服务器直接暴露在公网上,并且未使用CDN和反向代理服务器时:

可以直接使用remote_addr。如 PHP 可以直接使用

$_SERVER['REMOTE_ADDR']

这时候,HTTP_X_FORWARDED_FOR 和 HTTP_X_REAL_IP 都是可以被伪造的,但REMOTE_ADDR是客户端和服务器的握手IP,即client的出口IP,伪造不了。
比如用下面这条命令来请求一个php文件,并且输出$_SERVER信息

curl http://10.200.21.32/test.php -H 'X-Forwarded-For: unkonw, <alert>aa,11.22.33.44,11</alert>" 1.1.1.1' -H 'X-Real-IP: 2.2.2.2, <a>'

结果是(只取部分信息,10.100.11.25是我电脑的IP,服务器是内网服务器,所以不会有公网IP)

[HTTP_X_FORWARDED_FOR] => unkonw, <alert>aa,11.22.33.44,11</alert>" 1.1.1.1
[REMOTE_ADDR] => 10.100.11.25
[HTTP_X_REAL_IP] => 2.2.2.2, <a>

可以看到,HTTP_X_FORWARDED_FOR 和 HTTP_X_REAL_IP 是万万不可直接拿来用的。使用$remote_addr是明智的选择。

比如我们伪造一下来源IP发给著名的 ip138.com

curl http://1212.ip138.com/ic.asp -H 'X-Forwarded-For: unkonw, <alert>aa,11.22.33.44,11</alert>" 1.1.1.1'

它原样输出了我们伪造的XFF。

2.2.在代理服务器或CDN之后的业务服务器

前提:上面的每一层代理或CDN,都将原始请求的 remote_addr 一路传递下去。我们先来看其中一种方案。

如果web服务器上层也是使用nginx做代理或负载均衡,则需要在代理层的nginx配置中明确XFF参数,累加传递上一个请求方的IP到header请求中。以下是代理层的nginx配置参数。

    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_set_header X-NginX-Proxy true;

如果web服务器前面使用了HAProxy,则需要增加以下配置来将用户的真实IP转发到web服务器。

    option forwardfor

如果想在业务服务器获取完整的链路信息,还是通过XFF获取,需要在nginx的配置中加一条配置,加上此配置可以让我们获取整个链路信息:

fastcgi_param  HTTP_X_FORWARDED_FOR $http_x_forwarded_for;

实测此参数最好加在被 include 的fastcgi.conf中,就是有一堆fastcgi_param配置的那个文件否则就写入location段。这个配置可能会影响你的nginx日志,这个后续会详细说明。如果不配置此项,则我们在WEB SERVER 上直接获取到的XFF信息则是上一个代理层的IP。当然,也不影响获取用户真实IP。不过如果你是在调试配置的情况下,就不方便查看整个链路了。

2.2.1 在只有一层代理的情况下

我们按上面的配置发起一个伪造请求, 10.100.11.25 是我电脑的IP,链路为:

10.100.11.25(client)->10.200.21.33(Proxy)->10.200.21.32(Web Server)

curl 请求:

curl http://10.200.21.33:88/test.php -H 'X-Forwarded-For: unkonw, <8.8.8.8> 1.1.1.1' -H 'X-Real-IP: 2.2.2.2'

结果如下:

[HTTP_X_FORWARDED_FOR] => unkonw, <8.8.8.8> 1.1.1.1, 10.100.11.25
[REMOTE_ADDR] => 10.200.21.33
[HTTP_X_REAL_IP] => 10.100.11.25

我们可以看到,XFF被附加上了我的IP,但前面的一系列伪造内容,可以轻易骗过很多规则,而HTTP_X_REAL_IP 则传递了我电脑的IP。因为在上面的配置中,X-Real-IP 已经被设置为握手 IP。 但多层代理之后,以上面的规则,显然 HTTP_X_REAL_IP 也不会是真实的用户IP了。而 HTTP_X_FORWARDED_FOR 则在原有信息(我们伪造的信息)之后附上了握手 IP 一起传递过来了。

2.2.2 在两层或更多代理的情况下

我们这里只测试两层,实际链路为:

10.100.11.25(client)->10.200.21.34(Proxy)->10.200.21.33(Proxy)->10.200.21.32(Web Server)

Curl 命令:

curl http://10.200.21.34:88/test.php -H 'X-Forwarded-For: unkonw, <8.8.8.8> 1.1.1.1' -H 'X-Real-IP: 2.2.2.2'

两层代理的情况下结果为:

[HTTP_X_FORWARDED_FOR] => unkonw, <8.8.8.8> 1.1.1.1, 10.100.11.25, 10.200.21.34
[REMOTE_ADDR] => 10.200.21.33
[HTTP_X_REAL_IP] => 10.200.21.34

根据上面的情况,怎么挑出真正的用户IP呢?设想三种方案:
* 第一层代理将用户的真实 IP 放在 X-Real-IP 中传递下去,后面的每一层都使用 X-Real-IP 继续往下传递。配置为:

proxy_set_header X-Real-IP $remote_addr;    # 针对首层代理,拿到真实IP
proxy_set_header X-Real-IP $http_x_real_ip; # 针对非首层代理,一直传下去
  • 从首层开始,将用户的真实IP 放在 X-Forwarded-For 中,而不是累加各层服务器的 IP,但这样也不够合理,因为丢掉了整个链路信息。配置为:
proxy_set_header X-Forwarded-For $remote_addr; # 针对首层代理
proxy_set_header X-Forwarded-For $http_x_forwarded_for; # 针对非首层代理
  • 从 X-Forwarded-For 中获取的用户真实IP,排除掉所有代理IP,取最后一个符合IP规则的,注意不是第一个,因为第一个可能是被伪造的(除非首层代理使用了握手会话 IP 做为值向下传递)。

一般CDN都会将用户的真实 IP 在XFF中传递下去。我们可以做几个简单的测试就能知道我们该怎么做。

注意:nginx配置的这两个变量:
* $proxy_add_x_forwarded_for 会累加代理层的IP向后传递
* $http_x_forwarded_for 仅仅是上层传过来的值

3.配合nginx realip模块获取用户真实IP

我们应该秉承一个原则:

能通过配置让事情变的更简单和通用的事儿,就不要用程序去解决。即环境对程序透明。这当然少不了系统运维人员的辛苦。

如果能在配置中理清,就不必用复杂的程序去解决,因为Server上可能有各种应用都要来获取用户IP,如果规则不统一,结果会不一致。
程序不知道链路到底经过了几层才转到web server上,所以让程序去做兼容并不是个好主意。索性就让程序把所有的代理都当成透明的好了。

终于说到重点了。上面介绍的三种方法中,如果不能保证前面的代理层使用我们指定的规则,这时候怎么办呢?只能使用第三种方法。然后我们将各层代理的IP排除在外,就取到了真实的用户IP。这个可以使用nginx的一个模块儿 realip_module 来实现。原理是从XFF中抛弃指定的代理层 IP,那么最后一个符合规则的就是用户 IP。也可以配合第一起方法一起使用。但无论如何,首层代理的规则最重要,直接影响后面的代理层和web service的接收结果。

nginx realip_module 模块需要在编译nginx的时候加上参数--with-http_realip_module

然后在nginx配置中增加以下配置(可以在http,server或location段中增加)

    # set user real ip to remote addr
    set_real_ip_from   10.200.21.0/24;
    set_real_ip_from   10.100.23.0/24;
    real_ip_header     X-Forwarded-For;
    real_ip_recursive on;

set_real_ip_from 后面是可信 IP 规则,可以有多条。如果启用CDN,知道CDN的溯源IP,也要加进来,除排掉可信的,就是用户的真实IP,会写入 remote addr这个变量中。

比如在PHP中可以使用$_SERVER['REMOTE_ADDR'] 来获取。而WEB SERVER 不使用任何反向代理时,也是取这个值,这就达到了我们之前所说的原则。

real_ip_recursive 是递归的去除所配置中的可信IP。如果只有一层代理,也可以不写这个参数。

然后我在外网请求一下,结果是这样的

[HTTP_X_FORWARDED_FOR] => unkonw, <8.8.8.8> 1.1.1.1, 112.193.23.51, 10.200.21.50
[REMOTE_ADDR] => 112.193.23.51

112.193.23.51 是 client 的 IP, 10.200.21.50 是WEB SERVER 前面的负载均衡。 真实IP拿到了。

再说下nginx日志

如果nginx日志中记录了XFF,那么可能会有一些是我们不想记录的,比如我们现在使用的默认的nginx日志格式为:

log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

这时候由于XFF里包含太多信息,甚至可能是一些伪造的未经过滤的文本,在使用和分析日志的时候会出现麻烦,所以我们干脆不记录它。nginx 的日志格式log_format还有一个默认值“combined”. 默认格式为:

log_format combined '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent"';

我们使用这个格式就好了。

总结

我们建议使用以下规则:
* 首层代理将握手 IP 附在 X-Forwarded-For 上一直向后传递(或者将 X-Forwarded-For 设置为握手 IP 向后传递),后面的每一层累加握手 IP 往后传递。
* 首层代理将握手 IP 设置为 HTTP 请求头的 X-Real-IP 中向后传递。后面的每一层原样传递下去(有则原样传递,无则设置为握手 IP )。

握手IP:即请求方的 remote_addr, 重要的话要说三遍:

运维很重要,首个代理层的处理方式很重要。

运维很重要,首个代理层的处理方式很重要。

运维很重要,首个代理层的处理方式很重要。

在只有运维最清楚网络环境的时候,尽量通过配置对应用透明。减少应用层的复杂判断。如果环境很复杂,比如使用了CDN,则有可能需要多方协调。

参考资料

  • http://nginx.org/en/docs/http/ngx_http_realip_module.html
  • https://www.zhihu.com/question/23810075
  • http://www.cnblogs.com/zhengyun_ustc/archive/2012/09/19/getremoteaddr.html
  • http://zhensheng.im/2013/08/31/1952/MIAO_LE_GE_MI
  • http://stackoverflow.com/questions/25929599
  • http://www.ttlsa.com/nginx/nginx-get-user-real-ip/
  • https://imququ.com/post/x-forwarded-for-header-in-http.html
  • http://freeloda.blog.51cto.com/2033581/1288553
  • http://nginx.org/en/docs/http/ngx_http_log_module.html

针对Yii框架的nginx配置

我曾经针对yii制作了 个nginx配置,其中包括了以下几项内容:

  • rewrite规则(try_file),需要nginx0.8.6版本以上支持。
  • 针对于icon, robots.txt文件的日志优化
  • .svn, .git,等版本控制文件的忽略,以及Mac本身索引文件目录
  • Yii框架本身应该禁止web访问的目录。
  • 图片等静态文件缓存优化

在这里分享一下demo

server {
    listen       80;
    server_name  youdomain.com;
    index index.html index.htm index.php;
    root  /home/wwwroot/htdocs/yii-1.1.8.r3324/demos/blog;
    #charset koi8-r;

    # 这里的main,是nginx默认的httpd段的一个日志格式定义
    access_log  /home/wwwlogs/localhost.access.log  main;
    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    #error_page   500 502 503 504  /50x.html;

    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }

    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }

    ################ Yii framework rule #################
    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ /(protected|framework|nbproject|themes/\w+/views|index-test\.php) {
        deny all;
        # for production
        internal;
        log_not_found off;
        access_log off;
    }
    ################ for Yii framework end #################

    location ~ \.php$ {
        fastcgi_pass   php;
        fastcgi_index  index.php;
        include fastcgi.conf;
    }

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    location ~ /(\.svn|\.git|\.ht|\.DS) {
        deny all;
        internal;
    }

    location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
         expires max;
         log_not_found off;
    }

}

Nginx gzip参数详解

这个模块支持在线实时压缩输出数据流
_ _使用范例_ _

gzip             on;
gzip_min_length  1000;
gzip_proxied     expired no-cache no-store private auth;
gzip_types       text/plain application/xml;

gzip

语法: gzip on|off

默认值: gzip off

作用域: http, server, location, if (x) location

开启或者关闭gzip模块

gzip_buffers

语法: gzip_buffers number size

默认值: gzip_buffers 4 4k/8k

作用域: http, server, location
设置系统获取几个单位的缓存用于存储gzip的压缩结果数据流。 例如 4 4k 代表以4k为单位,按照原始数据大小以4k为单位的4倍申请内存。 4 8k 代表以8k为单位,按照原始数据大小以8k为单位的4倍申请内存。

如果没有设置,默认值是申请跟原始数据相同大小的内存空间去存储gzip压缩结果。

gzip_comp_level

语法: gzip_comp_level 1..9

默认值: gzip_comp_level 1

作用域: http, server, location

gzip压缩比,1 压缩比最小处理速度最快,9 压缩比最大但处理最慢(传输快但比较消耗cpu)。

gzip_min_length

语法: gzip_min_length length

默认值: gzip_min_length 0

作用域: http, server, location
设置允许压缩的页面最小字节数,页面字节数从header头中的Content-Length中进行获取。

默认值是0,不管页面多大都压缩。

建议设置成大于1k的字节数,小于1k可能会越压越大。 即: gzip_min_length 1024

gzip_http_version

语法: gzip_http_version 1.0|1.1

默认值: gzip_http_version 1.1

作用域: http, server, location

识别http的协议版本。由于早期的一些浏览器或者http客户端,可能不支持gzip自解压,用户就会看到乱码,所以做一些判断还是有必要的。 注:21世纪都来了,现在除了类似于百度的蜘蛛之类的东西不支持自解压,99.99%的浏览器基本上都支持gzip解压了,所以可以不用设这个值,保持系统默认即可。

gzip_proxied

语法: gzip_proxied [off|expired|no-cache|no-store|private|no_last_modified|no_etag|auth|any] …

默认值: gzip_proxied off

作用域: http, server, location

Nginx作为反向代理的时候启用,开启或者关闭后端服务器返回的结果,匹配的前提是后端服务器必须要返回包含”Via”的 header头。

  • off – 关闭所有的代理结果数据的压缩
  • expired – 启用压缩,如果header头中包含 “Expires” 头信息
  • no-cache – 启用压缩,如果header头中包含 “Cache-Control:no-cache” 头信息
  • no-store – 启用压缩,如果header头中包含 “Cache-Control:no-store” 头信息
  • private – 启用压缩,如果header头中包含 “Cache-Control:private” 头信息
  • no_last_modified – 启用压缩,如果header头中不包含 “Last-Modified” 头信息
  • no_etag – 启用压缩 ,如果header头中不包含 “ETag” 头信息
  • auth – 启用压缩 , 如果header头中包含 “Authorization” 头信息
  • any – 无条件启用压缩

 

gzip_types

语法: gzip_types mime-type [mime-type …]

默认值: gzip_types text/html

作用域: http, server, location

匹配MIME类型进行压缩,(无论是否指定)”text/html”类型总是会被压缩的。
注意:如果作为http server来使用,主配置文件中要包含文件类型配置文件

http {
      include        conf/mime.types;
      ........
     }

 

gzip_vary

syntax: gzip_vary on|off

default: gzip_vary off

context: http, server, location

Enables response header of “Vary: Accept-Encoding”. Note that this header causes IE 4-6 not to cache the content due to a bug

注意:如果开启了这个参数,并且前端有一层缓存层的话,缓存命中率将大受影响

example:

gzip  on;
gzip_min_length  1k;
gzip_buffers     4 16k;
gzip_http_version 1.0;
gzip_comp_level 2;
gzip_types       text/plain text/javascript application/x-javascript text/css application/xml;
gzip_vary on;

nginx rewirte 规则出现emerg错误解决

nginx的rewrite规则中,如果包含大括号,则需要将此条规则中的匹配项用引号包含起来,否则会出现错误。

如:

rewrite ^/([a-zA-Z]{1,50})/api/([a-zA-Z]{1,50})$ /api/api.php?a=$1&t=$2;

如上面这条规则,用nginx -t测试规则是否成功时会出现以下错误:

[emerg]: directive “rewrite” is not terminated by “;”

正确的应该是这样的

rewrite "^/([a-zA-Z]{1,50})/api/([a-zA-Z]{1,50})$" /api/api.php?a=$1&t=$2;

用引号将包含大括号的规则包含起来,就不会出错了。

google apache 加速模块 mod-pagespeed

Google推出mod-pagespeed免费模块用于优化Apache HTTP服务器框架下的网站速度。该模块从多个方面对服务器运行速度进行优化,例如可以对图片进行再压缩,通过CMS(内容管理系统)改变网页构造但不改变CMS本身等。在此次开源之前,Google内部也一直使用该模块。

如果你在安装的时候出现

Public key for mod-pagespeed-beta_current_i386.rpm is not installed

则需要导入Google Public key:

wget https://dl-ssl.google.com/linux/linux_signing_key.pub
rpm –import linux_signing_key.pub

或者

rpm –import http://dl.google.com/linux/linux_signing_key.pub

OK,现在开始安装mod-pagespeed
Continue reading

htpasswd 命令用法

htpasswd建立和更新存储用户名、密码的文本文件, 用于对HTTP用户的basic认证。 如果htpasswd不能存取文件, 比如,不能写入到输出文件中,或者读取需要更新的文件, 它将不做任何改变,并返回一个出错代码。

htpasswd使用专为Apache作了修改的MD5或系统函数crypt()加密密码。 htpasswd所管理的文件可以包含两种类型的密码; 有些用户的密码使用MD5加密的,而同一个文件中的其他用户是用crypt()加密的。

概要
在linux下执行htpasswd 可出现如下提示:
htpasswd [-cmdpsD] passwordfile username
htpasswd -b[cmdpsD] passwordfile username password
htpasswd -n[mdps] username
htpasswd -nb[mdps] username password
Continue reading

nginx关闭默认站点(主机)或引导转向

无论是中国大陆变态的“监管”还是为抵制垃圾访问,我们都应该关闭nginx的默认站点,或者把这些垃圾流量转化为你的流量,让它跳转到你指定的网站。

对于nginx来说,即使是访问服务器上不存在的域名时,nginx也会返回一个出错页面“bad hostname”之类的。

解决方法是在nginx的配置文件中(nginx.conf)加入一个处理默认(就是不符合其他任何已有的vhost)server的项目:

server {
listen       80  default_server;
server_name  _;
return       444;
}

Continue reading

使用awstats自动分析Nginx日志

使用awstats可以分析apache日志,同样也可以分析nginx日志。本文将详细介绍自动定时切割nginx的访问日志,并使用awstats来定时分析nginx的日志的实现方法。

前言

本文中使用的是awstats 7.0版本。
此版本增加了对win7的支持以及一些更新的特性。

New features/improvements:
– Detect Windows 7.
– Can format numbers according to language.
– More mime types.
– Added geoip_asn_maxmind plugin.
– Geoip Maxmind city plugin have now override file capabilities to complete
missing entries in geoip maxmind database.
– Added graphgooglechartapi to use online Google chart api to build graph.
– Can show map of country to report countries when using graphgooglechartapi.
– Part of codes was change to use more functions and have a cleaner code.
– Added parameter to ignore missing log files when merging for a site on
multiple servers where a single server may not have created a log for a given day.
– Update robots database.
– Added Download tracking where certain mime types are defined as downloads
and HTTP status 206 is tracked as download continuation

Awstats 是在 SourceForge 上发展很快的一个基于 Perl 的 WEB 日志分析工具,一个充分的日志分析让 Awstats 显示您下列资料: Continue reading

nginx目录设置 alias 和 root

使用nginx设置root时要注意一个问题,就是如果该root设置的前端目录不是根目录,那么在写root的绝对地址时,要把前端目录的部分省略掉。
我们用设置虚拟目录指向的alias来和root比较一下就非常明显了

alias

location /abc/ {
    alias /home/html/abc/;
}

在这段配置下,http://test/abc/a.html就指定的是 /home/html/abc/a.html。这段配置亦可改成

root

location /abc/ {
    root /home/html/;
}

可以看到,使用root设置目录的绝对路径时,少了/abc,也就是说,使用root来设置前端非根目录时,nginx会组合root和location的路径。

另外,使用alias时目录名后面一定要加“/”

用nginx的反向代理搭建twitter API

以前用rabr这个第三方网页版客户端。由于不能再使用base认证,同时oauth认证居然也有问题。所以决定使用桌面版客户端加第三方twitter API.

本来想搭建一个php版的第三方twitter API.没想到发现nginx可以做反向代理。哈哈,以前没用过。用nginx做反向代理,比php的快多了。

使用如下例的nginx配置,可以迅速搭建一个基于nginx反向代理的twitter api.包括twitter search api.

将下面的api.twitter.me 和search.twitter.me换成你的域名。日志目录什么的,根据你的情况来定。

server {
    listen          80;
    server_name     api.twitter.me;

    access_log      /var/log/nginx/api.twitter.me.access_log;

    location / {
        proxy_pass              http://twitter.com/;
        proxy_redirect          off;
        proxy_set_header        X-Real-IP       $remote_addr;
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

server {
    listen          80;
    server_name     search.twitter.me;

    access_log      /var/log/nginx/search.twitter.access_log;

    location / {
        proxy_pass              http://search.twitter.com/;
        proxy_redirect          off;
        proxy_set_header        X-Real-IP       $remote_addr;
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}