Nginx
请注意
本文内容可能已过时,请自行甄别。
安装
安装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获取请求参数
下载的所有包,放在了/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.conf
的server
添加如下
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访问日志 IP统计 awk '{print $1}' access.log | sort | uniq -c|sort -n