13、反向代理模块
(1)、常用指令:
l proxy_connect_timeout:nginx将一个请求发送至upstream server之前等待的最大时长;
l proxy_cookie_domain:将upstreamserver通过Set-Cookie首部设定的domain属性修改为指定的值,其值可以为一个字符串、正则表达式的模式或一个引用的变量;
l proxy_cookie_path: 将upstream server通过Set-Cookie首部设定的path属性修改为指定的值,其值可以为一个字符串、正则表达式的模式或一个引用的变量;
l proxy_hide_header:设定发送给客户端的报文中需要隐藏的首部;
l proxy_pass:指定将请求代理至upstreamserver的URL路径;
l proxy_set_header:将发送至upsreamserver的报文的某首部进行重写;
l proxy_redirect:重写location并刷新从upstream server收到的报文的首部;
l proxy_send_timeout:在连接断开之前两次发送至upstreamserver的写操作的最大间隔时长;
例:
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;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 30;
proxy_send_timeout 15;
proxy_read_timeout 15;
(2)、proxy_pass 指令详解及案例
使用格式:
location / {
proxy_pass http://192.168.61.88/;
注意:这里backserver/最后面的/,要和location /的一致,有就要加上
}
这里location有2个例外:
n 当使用模式匹配,例~* xxx ,这里的uri就会补在http://back/后面
n 使用了url重定向rewrite的话,nginx将使用重定向后的uri补在http://back/后面
例1:
除了整个网站的代理,也可以代理一部分:
location /bbs/ {
proxy_pass http://192.168.61.88/bbs/;
}
例2:
特定后缀名反代,只要是jpeg结尾的都代理到后端服务器
location ~*\.(jpeg|gif)$ {
proxy_pass http://192.168.61.88;
}
注意:这个场景中\.(jpeg|gif)$ 这个uri是没有任何意义的,后端服务器只能保留服务器端地址,不然会出错。匹配到什么都会
原封不动补在服务器地址http://192.168.61.88后
例3:
还可以在location里面再嵌套一个location,某网站案例是这样写的
location / {
location /bbs {
。。。
}
}
例4:
在nginx中配置proxy_pass时,如果是按照^~匹配路径时,要注意proxy_pass后的url最后的/,当加上了/,相当于是绝对根路径,
则nginx不会把location中匹配的路径部分代理走;如果没有/,则会把匹配的路径部分也给代理走。
location ^~/static_js/
{
proxy_cache js_cache;
proxy_set_header Hostjs.test.com;
proxy_pass http://js.test.com/;
}
如上面的配置,如果请求的url是http://servername/static_js/test.html
会被代理成http://js.test.com/test.html
而如果这么配置
location ^~ /static_js/
{
proxy_cache js_cache;
proxy_set_header Hostjs.test.com;
proxy_pass http://js.test.com;
}
则会被代理到http://js.test.com/static_js/test.htm
当然,我们可以用如下的rewrite来实现/的功能
location ^~/static_js/
{
proxy_cache js_cache;
proxy_set_header Hostjs.test.com;
rewrite/static_js/(.+)$ /$1 break;
proxy_pass http://js.test.com;
}
例5:
在nginx中配置proxy_pass时,当在后面的url加上了/,相当于是绝对根路径,则nginx不会把location中匹配的路径部分代理走;
如果没有/,则会把匹配的路径部分也给代理走。
下面四种情况分别用http://192.168.1.4/proxy/test.html 进行访问。
第一种:
location /proxy/ {
proxy_pass http://127.0.0.1:81/;
}
会被代理到http://127.0.0.1:81/test.html 这个url
第二种(相对于第一种,最后少一个 /)
location /proxy/ {
proxy_pass http://127.0.0.1:81;
}
会被代理到http://127.0.0.1:81/proxy/test.html 这个url
第三种:
location /proxy/ {
proxy_pass http://127.0.0.1:81/ftlynx/;
}
会被代理到http://127.0.0.1:81/ftlynx/test.html 这个url。
第四种情况(相对于第三种,最后少一个 / ):
location /proxy/ {
proxy_passhttp://127.0.0.1:81/ftlynx;
}
会被代理到http://127.0.0.1:81/ftlynxtest.html 这个url
(3)、反代上游服务器记录客户端真实IP
向后端发送一些客户端的信息方法:
location /bbs/ {
proxy_passhttp://192.168.61.88/bbs/;
proxy_set_headerHost $host;
向后端发送客户端请求首部中的host信息
proxy_set_headerX-Real-IP $remote_addr;
向后端发送客户端的IP
}
proxy_set_header X-Real-IP $remote_addr;
这里发送了客户端的IP,后端服务器的日志记录格式也要做出一点修改才能把这个传过来的IP记录下来,以httpd的日志为例:
vim /etc/httpd/conf/httpd.conf
定位LogFormat第一行%h改为%{X-Real-IP}i 即可
注意:当后端服务器有多个虚拟主机,必须要加上proxy_set_headerHost $host; 把Host信息给后端虚拟主机做判断
(4)、前后端使用长连接和短连接的意义
模型:客户端----》Nginx反向代理----》后端服务器
l 客户端到nginx,这里一般都使用长连接,如果nginx上的缓存有客户端想要的内容,直接就返回给客户端了,没必要再把nginx到后端服务器之间做长连接浪费资源。所以就有proxy_version这个选项,可以对nginx和后端服务器之间指定1.0版本不支持长连接,节省资源
14、缓存
要使用缓存功能,安装的时候要启用才可以哦,这样./configure --add-module=../ngx_cache_purge-2.3
l nginx反向代理到后端服务器之间也可以使用https通信,但要1.7.8版本以后才支持。它有众多的proxy_ssl_xxxxx选项可用
l nginx反向代理可以通过缓存来加速客户端的访问,对应有proxy_cache_xxxx一系列设置指令。
l nginx的缓存用的是键值存储,键放在内存,值放在磁盘上。
l 缓存只能在http段定义,但可在http、server、location使用
proxy_cache指令
例:
proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=one:10m max_size=5000m
levels=1:2 ,:表示左边1级,该级用1个字符表示,右边2级,该级2个字符表示,如果还有3级就多加一个:表示.
keys_zone指定内存中的名称和大小10m
max_size表示使用多大的缓存空间
例,缓存后的数据存放格式:
/data/nginx/cache/c/29/b7f54b2df7773722d382f4809d65029c
l 什么情况下要缓存?默认GET HEAD,一般不会对Post缓存
proxy_cache_methodsGET HEAD;
l 某个请求被响应多少次才缓存下来?
语法: proxy_cache_min_uses number;
默认1分钟: proxy_cache_min_uses 1;
可用于:http, server, location
l proxy_cache_purge
#用于清除缓存,假设一个URL为http://my.domain.com/test.gif,通过访问http://my.domain.com/purge/test.gif可以清除该
URL的缓存
使用方法:
(a)、先在http段定义一个缓存区和路径,只能在http段定义,例:
proxy_temp_path/data0/proxy_temp_path;
proxy_cache_path/data0/proxy_cache_path levels=1:2 keys_zone=cache_one:200m inactive=1dmax_size=30g;
(b)、再到server段中添加相应的location启用这个缓存区,例如这里针对一些文件的缓存:
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|js|css)$
{
#使用web缓存区cache_one
proxy_cache cache_one;
#对不同http状态码缓存设置不同的缓存时间
proxy_cache_valid 200304 12h;
proxy_cache_valid 301302 1m;
proxy_cache_valid any1m;
#设置web缓存的key值,nginx根据key值md5哈希存储缓存,这里根据“域名、URI、参数”组合成key
proxy_cache_key$host$uri$is_args$args;
}
(c)、再设置一个用于清除缓存的URL
location ~ /purge(/.*)
{
#设置只允许指定的IP或IP段才可以清除URL缓存
allow 127.0.0.1;
allow 192.168.0.0/16;
deny all;
proxy_cache_purgecache_one $host$uri$is_args$args;
}
l proxy_cache_revalidate on | off
是否对过期的缓存内容重新做检验:
例如客户端请求一个数据,缓存里面发现存在数据,但已经过期,它会再询问服务器端缓存数据是否有改变,没改变的话只需更改
过期时间,不用再重新传输
l proxy_cache_use_stale error|timeout|invalid_header|http_500.....
如果缓存有相应的数据,但时间过期了,恰好后端服务器又故障不能访问了,这时应该怎么办?这里就是对应的设置
l proxy_cache_valid [code ...] time
每一种响应码的缓存时长
缓存时间设定?不用后端服务器定义的缓存时间? 通过后端服务器的响应码。这个选项还不明白具体意思
例:
proxy_cache_valid 200302 10m;
proxy_cache_valid301 1h;
proxy_cache_validany 1m;
l proxy_cache_bypass string
string可以为:$cookie_nocache,$arg_nocache,$http_authorization
设置哪种情况下不从缓存拿数据,例如用户的私人信息,cookie等
l proxy_connect_timeout 600;
nginx重新封装客户端发送到后端服务器的过期时间,发起握手等候响应超时时间
l proxy_read_timeout 600;
连接成功后_等候后端服务器响应时间_其实已经进入后端的排队之中等候处理
l proxy_send_timeout 600;
后端服务器数据回传时间_就是在规定时间内后端服务器必须传完所有的数据
l proxy_hide_header
nginx重新封装取得的内容返回给客户端时,需要隐藏的头部信息
l proxy_pass_request_header on |off
proxy_pass_request_bodyon | off
这两项说明是否把客户端请求的头部或实体原封不动的发送到后端服务器
l proxy_buffers 4 32k;
接受后端服务器内容的缓存,这里指4段缓存空间,每段32k
l proxy_buffer_size 16k;
代理请求缓存区_这个缓存区间会保存用户的头信息供nginx进行规制处理_一般只要能保存下头信息即可
l proxy_busy_buffers_size 64k;
如果系统很忙的时候可以申请更大的proxy_buffers官方推荐*2
l proxy_temp_file_write_size 64k;
缓存临时文件的大小
l proxy_next_upstream http_502 http_504 error timeout invalid_header;
如果后端的服务器返回502/504、执行超时等错误,自动将请求转发到upstream负载均衡池中的另一台服务器,实现故障转移
l 一个缓存使用案例,只写了必须的,其余内容省略:
...
http
{
#注意:proxy_temp_path和proxy_cache_path指定的路径必须在同一分区
proxy_temp_path/data0/proxy_temp_path;
#设置web缓存区名称为cache_one,内存缓存空间大小为500MB,自动清除超过1天没有被访问的缓存数据,硬盘缓存空间大小为30GB
proxy_cache_path/data0/proxy_cache_path levels=1:2 keys_zone=cache_one:200m inactive=1dmax_size=30g;
server
{
listen 80;
server_name dx.com;
location /
{
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_pass http://my_server_pool;
}
location ~.*\.(gif|jpg|jpeg|png|bmp|swf|js|css)$
{
#使用web缓存区cache_one
proxy_cache cache_one;
#对不同http状态码缓存设置不同的缓存时间
proxy_cache_valid 200 304 12h;
proxy_cache_valid 301 302 1m;
proxy_cache_valid any 1m;
#设置web缓存的key值,nginx根据key值md5哈希存储缓存,这里根据“域名、URI、参数”组合成key
proxy_cache_key $host$uri$is_args$args;
#反向代理
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For$remote_addr;
proxy_pass http://my_server_pool;
}
#用于清除缓存,假设一个URL为http://my.domain.com/test.gif,通过访问http://my.domain.com/purge/test.gif可
以清除该URL的缓存
location ~ /purge(/.*)
{
#设置只允许指定的IP或IP段才可以清除URL缓存
allow 127.0.0.1;
allow 192.168.0.0/16;
deny all;
proxy_cache_purge cache_one$host$uri$is_args$args;
}
}
15、upstream 负载均衡模块
还记得前面说过的proxy_pass吧,后面只能跟一个主机名,upstream可以把多个主机做成一个组,给proxy_pass使用,实现负载均衡。可以用在proxy_pass, fastcgi_pass, uwsgi_pass, scgi_pass, and memcached_pass上。默认的调度方法是加权轮询
语法:
Syntax: upstream name { ... }
Default: ―
Context: http
只能用在http
里面可以使用的一些参数:
l ip_hash 类似LVS的SH的一种算法
l max_fails=number 健康状态监测次数,达到次数就把该后端服从列表中移除。如果恢复的话会自动加到列表里
l fail_timeout=time 健康状态监测时间
l backup 标记为备用服务器,类似LVS中的sorry server.其他服务器都不可用的时候这个服务器就会启用
l down 把对应服务器标志为不可用,通常和IP_hash结合使用
例1:
upstream backend {
server backend1.example.com weight=5;
server backend2.example.com:8080;
server unix:/tmp/backend3;
server backup1.example.com:8080 backup;
server backup2.example.com:8080 backup;
}
server {
location / {
proxy_pass http://backend;
}
}
例2:
upstream backend {
ip_hash; 把同一个IP地址的客户都调度到某台后端服务器,类似于IPVS的sh算法。它会把IP做hash先
server backend1.example.com;
server backend2.example.com;
server backend3.example.com down;
server backend4.example.com;
}
例3:
upstream backend {
server backend1.example.com max_fails=2fail_timeout=1;
server backend2.example.com;
server backend3.example.com down;
server backend4.example.com;
}
(2)、upstream内置变量
1. $upstream_addr 上游服务器地址
2. $upstream_cache_status 缓存状态
自定义响应首部:
add_headerx-via $server_addr 添加一个x-via字段显示服务器地址
add_headerx-cache $upstream_cache_status 添加一个x-cache字段,显示缓存是否命中
(3)、sticky指令
sticky 新版基于cookie绑定session
stick_cookie_insert 老版1.5.7之前基于cookie绑定session
这个指令有3个方法:
(a)、cookie
当客户端第一次访问nginx时,nginx会给它生成一个cookie返回做标识
upstream backend {
server backend1.example.com;
server backend2.example.com;
sticky cookie srv_id expires=1h domain=.example.com path=/;
}
(b)、route
它会在每个上游服务器加一个route id,当客户第一次请求过来,nginx就会根据upstream挑选一个上游服务器,上
游服务器根据里面设置的route值一并返回给客户,nginx以后就基于这个route值做调度
map$cookie_jsessionid $route_cookie {
~.+\.(?P<route>\w+)$ $route;
}
map$request_uri $route_uri {
~jsessionid=.+\.(?P<route>\w+)$$route;
}
upstream backend {
server backend1.example.com route=a;
server backend2.example.com route=b;
sticky route $route_cookie $route_uri;
}
(c)、learn
least_conn 调度方法,最少连接,相当于LVS的加权最少连接
keepalive 持久连接,一般不用在http server上,会有损害。多用于后端是memcached,因为nginx和memcached之间会大量交换查
询信息,不用多次建立连接
例:
upstream memcached_backend {
server 127.0.0.1:11211;
server 10.0.0.2:11211;
keepalive 32;
}
server {
...
location /memcached/ {
set $memcached_key $uri;
memcached_pass memcached_backend;
}
}
(4)、health_check指令
health_check 外部健康检测功能,应用层检测。其实upstream里已经有健康检测,但没health_check完善。用在location中。
注意:使用health_check的时候,建议关闭访问日志。
例:
location / {
proxy_pass http://backend;
health_check;
}
参数:
interval=time检测间隔时间,默认5秒
fails=number失败检测次数,默认1次
passes=number成功检测次数,默认1次
uri=uri请求资源设置,默认/,首页
match=name根据上面请求资源页面,应该包含这个设置的字串或内容,默认返回代码为2xx或3xx(重定向)算成功
例:
http {
server {
...
location / {
proxy_pass http://backend;
health_check match=welcome;
}
}
match welcome {
status 200; 指明响应码
header Content-Type = text/html; 指明头部
body ~ "Welcome to nginx!"; 指明实体内容,还使用了模式匹配
}
}
(5)、nginx upstream 容错机制
(a)nginx 判断节点失效状态
Nginx 默认判断失败节点状态以 connectrefuse 和 time out 状态为准,不以 HTTP 错误状态进行判断失败,因为 HTTP 只要能返回状态说明该节点还可以正常连接,所以 nginx 判断其还是存活状态;除非添加了proxy_next_upstream 指令设置对 404 、 502 、 503 、 504 、 500 和 time out 等错误进行转到备机处理,在next_upstream 过程中,会对 fails 进行累加,如果备用机处理还是错误则直接返回错误信息(但 404 不进行记录到错误数,如果不配置错误状态也不对其进行错误状态记录),综述, nginx 记录错误数量只记录timeout 、 connect refuse 、 502 、 500 、 503 、 504 这 6 种状态, timeout 和 connect refuse是永远被记录错误状态,而 502 、 500 、 503 、 504 只有在配置proxy_next_upstream 后 nginx 才会记录这 4 种 HTTP 错误到 fails 中,当 fails 大于等于 max_fails 时,则该节点失效;
(b)nginx 处理节点失效和恢复的触发条件
nginx 可以通过设置 max_fails (最大尝试失败次数)和fail_timeout (失效时间,在到达最大尝试失败次数后,在fail_timeout 的时间范围内节点被置为失效,除非所有节点都失效,否则该时间内,节点不进行恢复)对节点失败的尝试次数和失效时间进行设置,当超过最大尝试次数或失效时间未超过配置失效时间,则 nginx 会对节点状会置为失效状态,nginx 不对该后端进行连接,直到超过失效时间或者所有节点都失效后,该节点重新置为有效,重新探测;
(c)所有节点失效后 nginx 将重新恢复所有节点进行探测
如果探测所有节点均失效,备机也为失效时,那么nginx 会对所有节点恢复为有效,重新尝试探测有效节点,如果探测到有效节点则返回正确节点内容,如果还是全部错误,那么继续探测下去,当没有正确信息时,节点失效时默认返回状态为 502 ,但是下次访问节点时会继续探测正确节点,直到找到正确的为止。
16、fastcgi
让php在nginx下工作于fastcgi,即FPM
(1)、安装
yum install php-fpm
如果php和nginx不在同一台机器,php配置文件中要改一下client监听端口,允许nginx访问
打开vim /etc/nginx/nginx.conf,最后面有php配置的案例
# proxy the PHP scripts to Apache listening on127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI serverlistening on 127.0.0.1:9000
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000; #传到哪个服务器
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; #把当前php页面的url传递给后端服务
器
# include fastcgi_params; #使用扩展的fastcgi参数
#}
(2)、/etc/nginx/conf.d/下应该有fastcgi_params,它的作用是把当前服务器的信息存放到变量中,传递给php服务器,让其了解
情况
例如其中一行内容:
fastcgi_param QUERY_STRING $query_string;
最右边$query_string是nginx的变量,赋值给QUERY_STRING
注意:这个文件默认的内容是不适合nginx使用的,会启用不了php的,要做修改
编辑/etc/nginx/fastcgi_params,将其内容更改为如下内容:
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
并在所支持的主页面格式中添加php格式的主页,类似如下:
location/ {
root html;
index index.php index.html index.htm;
}
(3)、再安装php-mysql,就可以连接mysql了
(4)、yum install mysql
service mysqld start
(5)、 编辑index.php首页
添加以下内容测试mysql的连接
<?php $conn =mysql_connect('127.0.0.1','root','');
if($conn)
echo succ;
else
echo fail;
mysql_close();
?>
17、Nginx 日志配置
(1)、日志格式
log_format指令用来设置日志的记录格式,语法:
log_format name format [format...]
name 表示该日志模板的名称,format表示格式。log_format有一个默认的、无须设置的combined日志格式设置。
例:
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent"$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
注意:假设将nginx服务器作为web服务器,位于负载均衡设备、squid、nginx反向代理之后,就不能获取到客户端的真实IP地址
了。原因是经过反向代理后,由于在客户端和WEB服务器之间增加了中间层,因此web服务器无法直接拿到客户端的ip,通过
$remote_addr变量拿到的将是反向代理服务器的IP地址。但是,反向代理服务器在转发请求的http头信息中,可以增加X-
Forwarded-For信息,用于记录原有的客户端IP地址和原来客户端请求的服务器地址。
这个时候就要用log_format指令来设置日志格式,让日志记录X-Forwarded-For信息中的IP地址,即客户的真实IP。
log_format main '$http_x_forwarded_for - $remote_user[$time_local] "$request" '
'$status $body_bytes_sent"$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
(2)、日志使用
log_format指令设置了日志格式之后,需要用access_log指定日志文件存放路径。例:
access_log /data/logs/xx.log main;
main为刚才定义的日志模板
(3)、日志文件的切割
生产环境中的服务器,日志文件增长速度非常快,日志太大会严重影响服务器效率,所以要对日志文件进行定时切割。可以按年、
月、日、小时来切割。一般常用日来切割。
方法:
mv /data/logs/access.log /data/logs/20151010.log
kill -USR1 Nginx主进程号
首先通过mv命令将日志文件重命名为20151010.log,然后发送kill -USR1信号给Nginx的主进程号,让Nginx重新生成一个新的日志
文件access.log。同时,error.log文件也会自动生成。
如果nginx.conf配置文件中使用 pid/var/run/nginx/nginx.pid指令,可以通过cat这个pid文件获得nginx的主进程号,命令如
下:
kill-USR1 `cat /var/run/nginx/nginx.pid`
要每天定时切割文件就要用到脚本和crontab了
每天切割脚本如下:
#!/bin/bash
mkdir -p${logs_path}$(date -d "yesterday" "+%Y")$(date -d"yesterday" "+%m")$(date -d "yesterday""+%d")
mv ${logs_path}/access.log ${logs_path}/$(date -d "yesterday""+%m")$(date -d "yesterday" "+%d").log
mv ${logs_path}/error.log ${logs_path}/$(date -d "yesterday""+%m")$(date -d "yesterday" "+%d").log
kill -USR1 `cat /var/run/nginx/nginx.pid`
crontab设置:
crontab -e
00 00 * * * /bin/bash /root/test.sh
18、其他配置
server_tokens off; http段中使用,当出现404等错误时,是否显示详细的服务器等信息
ignore_invalid_headers on; 忽略错误的头部信息
server_names_hash_max_size 256;
server_names_hash_bucket_size 64; 这两项,把服务器名称hash后放内存中,更快