Nginx

linuxnginx约 2833 字大约 9 分钟

请注意

本文内容可能已过时,请自行甄别。

安装

安装Nginx

nginx默认使用80端口,请确保80未被使用

Nginx安装包

wget http://www.nginx.org/download/nginx-[version].tar.gz

Nginx cache purge 模块(可选)

# wget http://labs.frickle.com/files/ngx_cache_purge-[version].tar.gz

编译安装

./configure \
--prefix=/usr/local/nginx-[version] \
--with-http_stub_status_module \
--with-http_ssl_module \
--with-http_realip_module \ 
--add-module=../ngx_cache_purge-1.3

# make
# make install

启动

/usr/local/nginx-[version]/sbin/nginx   #启动
/usr/local/nginx-[version]/sbin/nginx -t #测试,检测配置
/usr/local/nginx-[version]/sbin/nginx -s stop
/usr/local/nginx-[version]/sbin/nginx -s reload

打开浏览器,访问nginx地址,出现welcome nginx则配置成功

日志格式

日志变量(log_format)

$args                    #请求中的参数值
$query_string            #同 $args
$arg_NAME                #GET请求中NAME的值
$is_args                 #如果请求中有参数,值为"?",否则为空字符串
$uri                     #请求中的当前URI(不带请求参数,参数位于$args),可以不同于浏览器传递的$request_uri的值,它可以通过内部重定向,或者使用index指令进行修改,$uri不包含主机名,如"/foo/bar.html"。
$document_uri            #同 $uri
$document_root           #当前请求的文档根目录或别名
$host                    #优先级:HTTP请求行的主机名>"HOST"请求头字段>符合请求的服务器名.请求中的主机头字段,如果请求中的主机头不可用,则为服务器处理请求的服务器名称
$hostname                #主机名
$https                   #如果开启了SSL安全模式,值为"on",否则为空字符串。
$binary_remote_addr      #客户端地址的二进制形式,固定长度为4个字节
$body_bytes_sent         #传输给客户端的字节数,响应头不计算在内;这个变量和Apache的mod_log_config模块中的"%B"参数保持兼容
$bytes_sent              #传输给客户端的字节数
$connection              #TCP连接的序列号
$connection_requests     #TCP连接当前的请求数量
$content_length          #"Content-Length" 请求头字段
$content_type            #"Content-Type" 请求头字段
$cookie_name             #cookie名称
$limit_rate              #用于设置响应的速度限制
$msec                    #当前的Unix时间戳
$nginx_version           #nginx版本
$pid                     #工作进程的PID
$pipe                    #如果请求来自管道通信,值为"p",否则为"."
$proxy_protocol_addr     #获取代理访问服务器的客户端地址,如果是直接访问,该值为空字符串
$realpath_root           #当前请求的文档根目录或别名的真实路径,会将所有符号连接转换为真实路径
$remote_addr             #客户端地址
$remote_port             #客户端端口
$remote_user             #用于HTTP基础认证服务的用户名
$request                 #代表客户端的请求地址
$request_body            #客户端的请求主体:此变量可在location中使用,将请求主体通过proxy_pass,fastcgi_pass,uwsgi_pass和scgi_pass传递给下一级的代理服务器
$request_body_file       #将客户端请求主体保存在临时文件中。文件处理结束后,此文件需删除。如果需要之一开启此功能,需要设置client_body_in_file_only。如果将次文件传 递给后端的代理服务器,需要禁用request body,即设置proxy_pass_request_body off,fastcgi_pass_request_body off,uwsgi_pass_request_body off,or scgi_pass_request_body off
$request_completion      #如果请求成功,值为"OK",如果请求未完成或者请求不是一个范围请求的最后一部分,则为空
$request_filename        #当前连接请求的文件路径,由root或alias指令与URI请求生成
$request_length          #请求的长度 (包括请求的地址,http请求头和请求主体)
$request_method          #HTTP请求方法,通常为"GET"或"POST"
$request_time            #处理客户端请求使用的时间,单位为秒,精度毫秒; 从读入客户端的第一个字节开始,直到把最后一个字符发送给客户端后进行日志写入为止。
$request_uri             #这个变量等于包含一些客户端请求参数的原始URI,它无法修改,请查看$uri更改或重写URI,不包含主机名,例如:"/cnphp/test.php?arg=freemouse"
$scheme                  #请求使用的Web协议,"http" 或 "https"
$server_addr             #服务器端地址,需要注意的是:为了避免访问linux系统内核,应将ip地址提前设置在配置文件中
$server_name             #服务器名
$server_port             #服务器端口
$server_protocol         #服务器的HTTP版本,通常为 "HTTP/1.0" 或 "HTTP/1.1"
$status                  #HTTP响应代码
$time_iso8601            #服务器时间的ISO 8610格式
$time_local              #服务器时间(LOG Format 格式)
$cookie_NAME             #客户端请求Header头中的cookie变量,前缀"$cookie_"加上cookie名称的变量,该变量的值即为cookie名称的值
$http_NAME               #匹配任意请求头字段;变量名中的后半部分NAME可以替换成任意请求头字段,如在配置文件中需要获取http请求头:"Accept-Language",$http_accept_language即可
$http_cookie
$http_host               #请求地址,即浏览器中你输入的地址(IP或域名)
$http_referer            #url跳转来源,用来记录从那个页面链接访问过来的
$http_user_agent         #用户终端浏览器等信息
$http_x_forwarded_for  #客户端地址(有反向代理时使用)
$sent_http_NAME          #可以设置任意http响应头字段;变量名中的后半部分NAME可以替换成任意响应头字段,如需要设置响应头Content-length,$sent_http_content_length即可
$sent_http_cache_control
$sent_http_connection
$sent_http_content_type
$sent_http_keep_alive
$sent_http_last_modified
$sent_http_location
$sent_http_transfer_encoding

默认日志格式

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

#main为日志格式名

可以根据自己的情况定义不同的log格式.然后在日志的 path后调用 access_log logs/it_access.log main;

当日志文件中记录的值为"-"时,表示为空 .

自定义的格式

log_format logstash '$remote_addr|$http_host|$request|$http_referer|$status |$http_user_agent|$request_time|$remote_user';

lua获取请求参数

conf
conf

下载的所有包,放在了/opt/packages目录下

安装依赖

yum -y install gcc gcc-c++ glib* make autoconf openssl openssl-devel \
libxslt-devel gd gd-devel pcre pcre-devel  readline-devel  wget curl

下载安装包

nginx


wget http://nginx.org/download/nginx-1.12.2.tar.gz

tar -xvf nginx-1.12.2.tar.gz

ngx_devel_kit

wget https://github.com/simplresty/ngx_devel_kit/archive/v0.3.0.tar.gz
tar zxvf v0.3.0.tar.gz

# 放着,一会编译ngxin时导入。

lua-nginx-module

wget https://github.com/openresty/lua-nginx-module/archive/v0.10.13.tar.gz
tar zxvf v0.10.13.tar.gz

# 放着,一会编译ngxin时导入。

安装LuaJIT

wget http://luajit.org/download/LuaJIT-2.0.5.tar.gz
tar -zxvf  LuaJIT-2.0.5.tar.gz
cd LuaJIT-2.0.5
make install PREFIX=/usr/local/LuaJIT

输出 以下内容则成功

==== Successfully installed LuaJIT 2.0.5 to /usr/local/LuaJIT ====

修改环境变量

export LUAJIT_LIB=/usr/local/LuaJIT/lib
export LUAJIT_INC=/usr/local/LuaJIT/include/luajit-2.0

source /etc/profile

编译安装nginx

查看编译参数, 避免之前的模块路径错误

nginx -V 

新建用户,不新建,configure时取消参数--user=nginx

useradd -M -s /sbin/nologin nginx 

编译安装

./configure --user=nginx --group=nginx --prefix=/usr/local/nginx --with-file-aio \
--with-http_ssl_module --with-http_realip_module --with-http_addition_module \
--with-http_xslt_module --with-http_image_filter_module --with-http_sub_module \
--with-http_dav_module --with-http_flv_module --with-http_mp4_module \
--with-http_gunzip_module --with-http_gzip_static_module \
--with-http_auth_request_module --with-http_random_index_module \
--with-http_secure_link_module --with-http_degradation_module \
--with-http_stub_status_module \
--with-ld-opt=-Wl,-rpath,/usr/local/LuaJIT/lib \
--add-module=/opt/packages/ngx_devel_kit-0.3.0 \
--add-module=/opt/packages/lua-nginx-module-0.10.13
make -j2 && make install

测试lua

修改nginx.confserver 添加如下

location /lua { 
    default_type 'text/plain'; 
    content_by_lua 'ngx.say("lua install success")'; 
}

重载nginx

nginx -s reload

请求

curl http://127.0.0.1/lua

# lua install success 

安装 cjson

如果需要lua解析json,可安装此模块

wget http://www.kyne.com.au/~mark/software/download/lua-cjson-2.1.0.tar.gz

tar xvf lua-cjson-2.1.0.ta.gz

cd lua-cjson-2.1.0

make

如若报错如下

cc -c -O3 -Wall -pedantic -DNDEBUG  -I/usr/local/include -fpic -o lua_cjson.o lua_cjson.c
lua_cjson.c:43:17: 致命错误:lua.h:没有那个文件或目录
 #include <lua.h>
                 ^
编译中断。
make: *** [lua_cjson.o] 错误 1

修改Makefile 这两处

PREFIX =            /usr/local/LuaJIT
LUA_INCLUDE_DIR =   $(PREFIX)/include/luajit-2.0

复制cjson.so

 cp cjson.so /usr/local/LuaJIT/lib/lua/5.1/
 chmod 755 /usr/local/LuaJIT/lib/lua/5.1/cjson.so 

使用lua 去rewrite路由

location /ztest {
	# 请求体的size大于nginx配置里的client_body_buffer_size
	# 则会导致请求体被缓冲到磁盘临时文件里,client_body_buffer_size默认是8k或者16k
	# 如果考虑性能,可以使用ngx.req.get_body_file(),见后续
	
	client_max_body_size  100m ;
    client_body_buffer_size  100m ;
    set $proxy '';
        rewrite_by_lua_block {
            local request_method = ngx.var.request_method
            if request_method == "GET" then
                local arg = ngx.req.get_uri_args()["proxy"] or 0
                ngx.var.proxy = arg
            elseif request_method == "POST" then
                ngx.req.read_body()
                local jkdata = ngx.req.get_body_data()
                --ngx.print(jkdata)
                if jkdata then
                	--如果传进来的是 json 通过这种方式解析,
                    --cjson = require "cjson"
                    --jkval = cjson.decode(jkdata)
                    --ngx.var.proxy = valp["proxy"]
                    # 这里测试下,使用正则去匹配了IP
                    ngx.var.proxy = jkdata:match("(%d+%.%d+%.%d+%.%d+)")
                    --ngx.var.proxy = jkval["proxy"]
                end
            end
        }
    include     /usr/local/nginx/conf/uwsgi_params;
    proxy_pass  $proxy:18001;
    access_log logs/aaa_access.log;
}

ngx.req.get_body_file()

ngx.req.read_body()
body_data = ngx.req.get_body_data()
if not body_data then
    local datafile = ngx.req.get_body_file()
    if not datafile then
        error_code = 1
        error_msg = "no request body found"
    else
        local fh, err = io.open(datafile, "r")
        if not fh then
            error_code = 2
            error_msg = "failed to open " .. tostring(datafile) .. "for reading: " .. tostring(err)
        else
            fh:seek("set")
            body_data = fh:read("*a")
            fh:close()
            if body_data == "" then
                error_code = 3
                error_msg = "request body is empty"
            end
        end
    end
 end

相关包

链接: https://pan.baidu.com/s/1nq9pOQO7uj88DwfHaT0EDg 提取码: p3fh

nginx负载与反代

nginx 负载

新建配置文件blance-test.conf

在nginx.conf 中include blance-test.conf

upstream blance-test {
    server 192.168.1.11:80;
    server 192.168.1.22:80;
}
server
{
    listen 80;
    server_name www.example.com; 
    location / {
        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_pass http://blance-test;
    }
    access_log logs/blance-test_access.log;
}

⚠️ proxy_set_header....

重点看下proxy_set_header X-Forwarded-For,当使用了代理时,web服务器无法取得真实IP,为了避免这个情况,代理服务器通常会增加一个叫做x_forwarded_for的头信息,连接它的客户端IP(即客户端IP)加到这个头信息里,这样就能保证网站的web服务器能获取到真实IP

$host: 请求中的主机头(Host)字段,如果请求中的主机头不可用或者空,则为处理请求的server名称(处理请求的server的server_name的值)。小写,不含端口。

$remote_addr; 客户端的IP地址(中间无代理则是真实客户端IP,有代理则是代理IP)

$proxy_add_x_forwarded_for; 就是$http_x_forwarded_for加上$remote_addr

官方解释

$proxy_add_x_forwarded_for

the “X-Forwarded-For” client request header field with the $remote_addr variable appended to it, separated by a comma. If the “X-Forwarded-For” field is not present in the client request header, the $proxy_add_x_forwarded_for variable is equal to the $remote_addr variable.

nginx 反向代理

可选配置,与http同级

   client_max_body_size 50m; #缓冲区代理缓冲用户端请求的最大字节数
    client_body_buffer_size 256k;
    client_header_timeout 3m;
    client_body_timeout 3m;
    send_timeout 3m;
    proxy_connect_timeout 300s; #nginx跟后端服务器连接超时时间(代理连接超时)
    proxy_read_timeout 300s; #连接成功后,后端服务器响应时间(代理接收超时)
    proxy_send_timeout 300s;
    proxy_buffer_size 64k; #设置代理服务器(nginx)保存用户头信息的缓冲区大小
    proxy_buffers 4 32k; #proxy_buffers缓冲区,网页平均在32k以下的话,这样设置
    proxy_busy_buffers_size 64k; #高负荷下缓冲大小(proxy_buffers*2)
    proxy_temp_file_write_size 64k; #设定缓存文件夹大小,大于这个值,将从upstream服务器传递请求,而不缓冲到磁盘
    proxy_ignore_client_abort on; #不允许代理端主动关闭连接

新建配置文件reverse-proxy.conf然后在nginx.conf 中include reverse-proxy.conf

    server {
        listen          7001;
        server_name     192.168.1.202:7001;
        charset utf-8;
        location /console {
           # proxy_set_header Host $host:$proxy_port;
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
            proxy_pass http://192.168.1.11:7001;
        }
        access_log logs/192.168.1.11:7001_access.log;
    }
    server {
        listen          8001;
        server_name     192.168.1.202:8001;
        charset utf-8;
        location / {
            proxy_set_header Host $host:$proxy_port;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
            proxy_pass http://192.168.1.11:8001;
        }
        access_log logs/192.168.1.11:8001_access.log;
    }

这里要说明下

server_name 
#主要用于配置基于名称的虚拟主机,可匹配正则,如果没有域名可填写IP,不填或随便填写一个
#nginx 根据 server_name 匹配 HTTP 请求头的 host,去决定使用那个 server
#如果都没有匹配则使用默认的。如果没有默认就是第一个server

$http_host 和 $host的区别

$host 上边描述过,主机头(Host)字段,如果不可用或空就是server_name的值。
$http_host  可以理解请求地址,即浏览器中你输入的地址(IP或域名)
那么这两个使用哪个好一些呢?
如果Host请求头部没有出现在请求头中,则$http_host值为空,但是$host值为主域名,
一般而言,会用$host代替$http_host,避免http请求中丢失Host头部的情况下Host不被重写。
如果对端口又要求可加上 :$proxy_port

官方关于nginx 代理模块的文章open in new window

Nginx访问日志 IP统计 awk '{print $1}' access.log | sort | uniq -c|sort -n