Nginx基础之错误页面配置/流量控制/访问控制/变量/监控/HTTPS配置/性能优化

16、nginx 错误页面配置

nginx错误页面包括404 403 500 502 503 504等页面,只需要在server中增加以下配置即可:

    error_page  404 403 500 502 503 504  /404.html;
                location = /404.html {
                        root   /usr/local/nginx/html;
                }

注意:

/usr/local/nginx/html/ 路径下必须有404.html这个文件!!!

404.html上如果引用其他文件的png或css就会有问题,显示不出来,因为其他文件的访问也要做配置;
为了简单,可以将css嵌入文件中,图片用base编码嵌入;如下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
        <title>404</title>
        <style>
            .layout-table{display:table;height:100%;width:100%;vertical-align: middle;margin-top:150px}
            .layout-table-cell{display: table-cell;vertical-align: middle;text-align:center}
            .layout-tip{font-size:28px;color:#373737;margin: 0 auto;margin-top:16px;border-bottom: 1px solid #eee;padding-bottom: 20px;width: 360px;}
            #tips{font-size:18px;color:#666666;margin-top:16px;}
        </style>
    </head>
    <body class="layui-layout-body">
        <div class="layui-layout layui-layout-admin">
            
            <div class="layui-body">
                <div class="layout-table">
                    <div class="layout-table-cell">
                        <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAV4AAACMCAYAAAA0qsGKAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkIwRDQ0ODRFMzMyODExRThBQ0Q5Q0UyNkNCMkE4MDk0IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkIwRDQ0ODRGMzMyODExRThBQ0Q5Q0UyNkNCMkE4MDk0Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QjBENDQ4NEMzMzI4MTFFOEFDRDlDRTI2Q0IyQTgwOTQiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QjBENDQ4NEQzMzI4MTFFOEFDRDlDRTI2Q0IyQTgwOTQiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4Qz6opAAAU5klEQVR42uxd3XXjthKe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" class="layout-img">
                        <p class="layout-tip">哎呀,找不到该页面啦!</p>
                        <p id="tips">请检查您的网络连接是否正常或者输入的网址是否正确</p>
                    </div>
                </div>
            </div>
        </div>
        
    </body>
</html>

** 展示效果:**
Nginx基础之错误页面配置/流量控制/访问控制/变量/监控/HTTPS配置/性能优化_第1张图片

过程演示:

[root@tnt-1 ~]# vim /etc/nginx/nginx.conf

#        error_page   500 502 503 504  /50x.html;
#        location = /50x.html {
#            root   html;
#        }
#
		 error_page 402 403 404 500 502 503 504 /404.html;
        location = /404.html {
        root /usr/local/nginx/html;
        }



#进主配置文件,找到原先默认的错误页面配置内容,注释掉或者修改掉.
#加入新的配置内容.写好路径.内容意思是只要出现402 403 500 502 503 504这些代码的,就会返回/404.html页面,并且去root /usr/local/nginx/html这个位置里面找这个页面.


[root@tnt-1 ~]# vim /usr/local/nginx/html/404.html

[root@tnt-1 ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

[root@tnt-1 ~]# nginx -s reload

# 然后自己定义的路径里创建一个404的页面.
# 页面代码上面有一个,复制粘贴就可以.
# 在vim创建的时候要用这个,因为这个页面代码内容特殊,可以预防复制粘贴不一致.
# :set paste 回车 然后按A 插入 
# 然后查看配置文件代码是否正常.
# 重新加载配置文件.
# 然后浏览器访问测试

Nginx基础之错误页面配置/流量控制/访问控制/变量/监控/HTTPS配置/性能优化_第2张图片

17、nginx 流量控制

求的数量。请求,可以是一个简单网站首页的GET请求,也可以是登录表单的 POST 请求。流量限制可以用作安全目的,比如可以减慢暴力密码破解的速率。通过将传入请求的速率限制为真实用户的典型值,并标识目标URL地址(通过日志),还可以用来抵御 DDOS 攻击。更常见的情况,该功能被用来保护上游应用服务器不被同时太多用户请求所压垮。

以下将会介绍Nginx的 流量限制 的基础知识和高级配置,”流量限制”在Nginx Plus中也适用。

1、Nginx如何限流

Nginx的”流量限制”使用漏桶算法(leaky bucket algorithm),该算法在通讯和分组交换计算机网络中广泛使用,用以处理带宽有限时的突发情况。就好比,一个桶口在倒水,桶底在漏水的水桶。如果桶口倒水的速率大于桶底的漏水速率,桶里面的水将会溢出;同样,在请求处理方面,水代表来自客户端的请求,水桶代表根据”先进先出调度算法”(FIFO)等待被处理的请求队列,桶底漏出的水代表离开缓冲区被服务器处理的请求,桶口溢出的水代表被丢弃和不被处理的请求。

2、配置基本的限流

“流量限制”配置两个主要的指令,limit_req_zonelimit_req,如下所示:

limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
server {
	location /login/ {
		limit_req zone=mylimit;

		proxy_pass http://my_upstream;
	}
}

limit_req_zone指令定义了流量限制相关的参数,而limit_req指令在出现的上下文中启用流量限制(示例中,对于”/login/”的所有请求)。

limit_req_zone指令通常在HTTP块中定义,使其可在多个上下文中使用,它需要以下三个参数:

  • Key - 定义应用限制的请求特性。示例中的 Nginx 变量$binary_remote_addr,保存客户端IP地址的二进制形式。这意味着,我们可以将每个不同的IP地址限制到,通过第三个参数设置的请求速率。(使用该变量是因为比字符串形式的客户端IP地址$remote_addr,占用更少的空间)
  • Zone - 定义用于存储每个IP地址状态以及被限制请求URL访问频率的共享内存区域。保存在内存共享区域的信息,意味着可以在Nginx的worker进程之间共享。定义分为两个部分:通过zone=keyword标识区域的名字,以及冒号后面跟区域大小。16000个IP地址的状态信息,大约需要1MB,所以示例中区域可以存储160000个IP地址。
  • Rate - 定义最大请求速率。在示例中,速率不能超过每秒10个请求。Nginx实际上以毫秒的粒度来跟踪请求,所以速率限制相当于每100毫秒1个请求。因为不允许”突发情况”(见下一章节),这意味着在前一个请求100毫秒内到达的请求将被拒绝。

当Nginx需要添加新条目时存储空间不足,将会删除旧条目。如果释放的空间仍不够容纳新记录,Nginx将会返回 503状态码(Service Temporarily Unavailable)。另外,为了防止内存被耗尽,Nginx每次创建新条目时,最多删除两条60秒内未使用的条目。

limit_req_zone指令设置流量限制和共享内存区域的参数,但实际上并不限制请求速率。所以需要通过添加

limit_req指令,将流量限制应用在特定的location或者server块。在上面示例中,我们对/login/请求进行流量限制。

现在每个IP地址被限制为每秒只能请求10次/login/,更准确地说,在前一个请求的100毫秒内不能请求该URL。

过程演示

[root@tnt-1 ~]# vim /etc/nginx/nginx.conf
 limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s;

        location / {
            root   html;
            index  index.html index.htm;
            limit_req zone=mylimit;
        }



#打开配置文件
#定义加入一个模块用来做限制.
#模块意思是,$binary_remote_addr zone 用二进制的方式去记录客户端的IP地址,并且定义一个名字叫做mylimit的地址用来存储所有来访问的客户端的IP地址,最后限制每个IP地址rate=1r/s,允许1秒钟不超过1个请求.内存共享区大小是10m.
#这个模块要写在server级别之外.为了便于测试,我们把rate=1r/s改成1秒1次.
#然后再在你需要引用这个模块的地方加上limit_req zone=mylimit;
#相当于先定义变量,然后引用变量.


[root@tnt-1 ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

[root@tnt-1 ~]# nginx -s reload

#测试配置文件
#重新加载


[root@tnt-2 ~]# curl -I http://120.25.2xx.2xx
HTTP/1.1 200 OK
Server: nginx/1.14.2
Date: Tue, 09 Jun 2020 09:20:41 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Mon, 01 Jun 2020 17:17:58 GMT
Connection: keep-alive
ETag: "5ed53846-264"
Accept-Ranges: bytes

[root@tnt-2 ~]# curl -I http://120.25.2xx.2xx
HTTP/1.1 503 Service Temporarily Unavailable
Server: nginx/1.14.2
Date: Tue, 09 Jun 2020 09:20:41 GMT
Content-Type: text/html
Content-Length: 9616
Connection: keep-alive
ETag: "5edf30fe-2590"

#然后浏览器或者curl测试.会发现第一次访问正常,快速访问的话就会被限制了.
#换一台服务器进行curl

3、处理突发

如果我们在100毫秒内接收到2个请求,怎么办?对于第二个请求,Nginx将给客户端返回状态码503。这可能并不是我们想要的结果,因为应用本质上趋向于突发性。相反地,我们希望缓冲任何超额的请求,然后及时地处理它们。我们更新下配置,在limit_req中使用burst参数:

location /login/ {
	limit_req zone=mylimit burst=20;
	proxy_pass http://my_upstream;
}

burst参数定义了超出zone指定速率的情况下(示例中的mylimit区域,速率限制在每秒10个请求,或每100毫秒一个请求),客户端还能发起多少请求。上一个请求100毫秒内到达的请求将会被放入队列,我们将队列大小设置为20。

这意味着,如果从一个给定IP地址发送21个请求,Nginx会立即将第一个请求发送到上游服务器群,然后将余下20个请求放在队列中。然后每100毫秒转发一个排队的请求,只有当传入请求使队列中排队的请求数超过20时,Nginx才会向客户端返回503。

过程演示

[root@tnt-1 ~]# vim /etc/nginx/nginx.conf
 location / {
            root   html;
            index  index.html index.htm;
            limit_req zone=mylimit burst=20;
        }

#打开配置文件.
#加上一个参数burst=20.
#这个参数理解为用来定义如果一定时间内超过了之前定义的速率1r/s以外的请求,会让第一个请求以外的其它请求去排队.超过了20个,才会丢弃掉返回503报错.就是最多让20个请求进行排队,最大延迟请求数量不大于20,在等待处理.

[root@tnt-1 ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

[root@tnt-1 ~]# nginx -s reload

#测配置文件.
#重新加载.
#然后测试

和上面一个测试例子对比,这里快速访问两次的话不会返回503.会发现会有一个稍微的卡顿,这里就可以理解为第二个请求在排队.最后返回的还是200.
Nginx基础之错误页面配置/流量控制/访问控制/变量/监控/HTTPS配置/性能优化_第3张图片

4、无延迟的排队

配置burst参数将会使通讯更流畅,但是可能会不太实用,因为该配置会使站点看起来很慢。在上面的示例中,队列中的第20个包需要等待2秒才能被转发,此时返回给客户端的响应可能不再有用。要解决这个情况,可以在burst参数后添加nodelay参数:

location /login/ {
	limit_req zone=mylimit burst=20 nodelay;

	proxy_pass http://my_upstream;
}

使用nodelay参数,Nginx仍将根据burst参数分配队列中的位置,并应用已配置的速率限制,而不是清理队列中等待转发的请求。相反地,当一个请求到达“太早”时,只要在队列中能分配位置,Nginx将立即转发这个请求。将队列中的该位置标记为”taken”(占据),并且不会被释放以供另一个请求使用,直到一段时间后才会被释放(在这个示例中是,100毫秒后)。

假设如前所述,队列中有20个空位,从给定的IP地址发出的21个请求同时到达。Nginx会立即转发这个21个请求,并且标记队列中占据的20个位置,然后每100毫秒释放一个位置。如果是25个请求同时到达,Nginx将会立即转发其中的21个请求,标记队列中占据的20个位置,并且返回503状态码来拒绝剩下的4个请求。

现在假设,第一组请求被转发后101毫秒,另20个请求同时到达。队列中只会有一个位置被释放,所以Nginx转发一个请求并返回503状态码来拒绝其他19个请求。如果在20个新请求到达之前已经过去了501毫秒,5个位置被释放,所以Nginx立即转发5个请求并拒绝另外15个。

效果相当于每秒10个请求的“流量限制”。如果希望不限制两个请求间允许间隔的情况下实施“流量限制”,nodelay参数是很实用的。

注意: 对于大部分部署,我们建议使用burstnodelay参数来配置limit_req指令。

5、高级配置示例

通过将基本的“流量限制”与其他Nginx功能配合使用,我们可以实现更细粒度的流量限制。

1、白名单

下面这个例子将展示,如何对任何不在白名单内的请求强制执行“流量限制”:

geo $limit {
	default 		1;
	10.0.0.0/8 		0;
	192.168.0.0/64 	0;
}

map $limit $limit_key {
	0 "";
	1 $binary_remote_addr;
}

limit_req_zone $limit_key zone=req_zone:10m rate=5r/s;

server {
	location / {
		limit_req zone=req_zone burst=10 nodelay;

		# ...
	}
}

这个例子同时使用了geomap指令。geo块将给在白名单中的IP地址对应的$limit变量分配一个值0,给其它不在白名单中的分配一个值1。然后我们使用一个映射将这些值转为key,如下:

  • 如果$limit变量的值是0,$limit_key变量将被赋值为空字符串
  • 如果$limit变量的值是1,$limit_key变量将被赋值为客户端二进制形式的IP地址

两个指令配合使用,白名单内IP地址的$limit_key变量被赋值为空字符串,不在白名单内的被赋值为客户端的IP地址。当limit_req_zone后的第一个参数是空字符串时,不会应用“流量限制”,所以白名单内的IP地址(10.0.0.0/8和192.168.0.0/24 网段内)不会被限制。其它所有IP地址都会被限制到每秒5个请求。

limit_req指令将限制应用到**/**的location块,允许在配置的限制上最多超过10个数据包的突发,并且不会延迟转发。

2、location 包含多limit_req指令

我们可以在一个location块中配置多个limit_req指令。符合给定请求的所有限制都被应用时,意味着将采用最严格的那个限制。例如,多个指令都制定了延迟,将采用最长的那个延迟。同样,请求受部分指令影响被拒绝,即使其他指令允许通过也无济于事。

扩展前面将“流量限制”应用到白名单内IP地址的例子:

http {
	# ...

	limit_req_zone $limit_key zone=req_zone:10m rate=5r/s;
	limit_req_zone $binary_remote_addr zone=req_zone_wl:10m rate=15r/s;

	server {
		# ...
		location / {
			limit_req zone=req_zone burst=10 nodelay;
			limit_req zone=req_zone_wl burst=20 nodelay;
			# ...
		}
	}
}

白名单内的IP地址不会匹配到第一个“流量限制”,而是会匹配到第二个req_zone_wl,并且被限制到每秒15个请求。不在白名单内的IP地址两个限制能匹配到,所以应用限制更强的那个:每秒5个请求。

6、配置流量控制相关功能

1、配置日志记录

默认情况下,Nginx会在日志中记录由于流量限制而延迟或丢弃的请求,如下所示:

2019/02/13 04:20:00 [error] 120315#0: *32086 limiting requests, excess: 1.000 by zone "mylimit", client: 192.168.1.2, server: nginx.com, request: "GET / HTTP/1.0", host: "nginx.com"

日志条目中包含的字段:

  • limiting requests - 表明日志条目记录的是被“流量限制”请求
  • excess - 每毫秒超过对应“流量限制”配置的请求数量
  • zone - 定义实施“流量限制”的区域
  • client - 发起请求的客户端IP地址
  • server - 服务器IP地址或主机名
  • request - 客户端发起的实际HTTP请求
  • host - HTTP报头中host的值

默认情况下,Nginx以error级别来记录被拒绝的请求,如上面示例中的[error]所示(Ngin以较低级别记录延时请求,一般是info级别)。如要更改Nginx的日志记录级别,需要使用limit_req_log_level指令。这里,我们将被拒绝请求的日志记录级别设置为warn

location /login/ {
	limit_req zone=mylimit burst=20 nodelay;
	limit_req_log_level warn;
	
	proxy_pass http://my_upstream;
} 

2、发送到客户端的错误代码

一般情况下,客户端超过配置的流量限制时,Nginx响应状态码为503(Service Temporarily Unavailable)。可以使用limit_req_status指令来设置为其它状态码(例如下面的444状态码):

location /login/ {
	limit_req zone=mylimit burst=20 nodelay;
	limit_req_status 444;
}

3、指定location拒绝所有请求

如果你想拒绝某个指定URL地址的所有请求,而不是仅仅对其限速,只需要在location块中配置deny all指令:

location /foo.php {
	deny all;
}

7、nginx 流量控制总结

以上已经涵盖了Nginx和Nginx Plus提供的“流量限制”的很多功能,包括为HTTP请求的不同loation设置请求速率,给“流量限制”配置burstnodelay参数。还涵盖了针对客户端IP地址的白名单和黑名单应用不同“流量限制”的高级配置,阐述了如何去日志记录被拒绝和延时的请求。

18、nginx 访问控制

1、nginx 访问控制模块

(1)基于IP的访问控制:http_access_module
(2)基于用户的信任登录:http_auth_basic_module

2、基于IP的访问控制

1、配置语法

Syntax:allow address | CIDR | unix: | all;
default:默认无
Context:http,server,location,limit_except

Syntax:deny address | CIDR | unix: | all;
default:默认无
Context:http,server,location,limit_except

2、配置测试

修改/etc/nginx/conf.d/access_mod.conf内容如下:

 location ~ ^/admin.html {
        root   /opt/app/code;
		deny 192.168.174.1;
		allow all;
        index  index.html index.htm;
    }

虚拟机宿主机IP为192.168.174.1,虚拟机IP为192.168.174.132,故这里禁止宿主机访问,允许其他所有IP访问。
宿主机访问http://192.168.174.132/admin.html,显示403 Forbidden
当然也可以反向配置,同时也可以使用IP网段的配置方式,如allow 192.168.174.0/24;,表示满足此网段的IP都可以访问。

3、局限性

remote_addr只能记录上一层与服务器直接建立连接的IP地址,若中间有代理,则记录的是代理的IP地址。
http_x_forwarded_for可以记录每一层级的IP。
Nginx基础之错误页面配置/流量控制/访问控制/变量/监控/HTTPS配置/性能优化_第4张图片

4、解决方法

(1)采用别的HTTP头信息控制访问,如HTTP_X_FORWARD_FOR(无法避免被改写)
(2)结合geo模块
(3)通过HTTP自定义变量传递

3、基于用户的信任登录

1、配置语法

Syntax:auth_basic string | off;
default:auth_basic off;
Context:http,server,location,limit_except

Syntax:auth_basic_user_file file;
default:默认无
Context:http,server,location,limit_except
file:存储用户名密码信息的文件。

2、配置示例

改名access_mod.confauth_mod.conf,内容如下:

 location ~ ^/admin.html {
        root   /opt/app/code;
        auth_basic "Auth access test!";
        auth_basic_user_file /etc/nginx/auth_conf;
        index  index.html index.htm;
    }

auth_basic不为off,开启登录验证功能,auth_basic_user_file加载账号密码文件。

3、建立口令文件

[root@web ~]# htpasswd -cm /etc/nginx/auth_conf user10
[root@web ~]# htpasswd -m /etc/nginx/auth_conf user20
[root@web ~]# cat /etc/nginx/auth_conf 
user10:$apr1$Cw6eF/..$MNBh6rvkvsfH9gDZ/kEhg/
user20:$apr1$tb6B8...$y28sfvudhfb4V8xPlvvi//

4、访问测试

Nginx基础之错误页面配置/流量控制/访问控制/变量/监控/HTTPS配置/性能优化_第5张图片

5、局限性

(1)用户信息依赖文件方式
(2)操作管理机械,效率低下

6、解决方法

(1)Nginx结合LUA实现高效验证
(2)Nginx和LDAP打通,利用nginx-auth-ldap模块
(3)Nginx只做中间代理,具体认证交给应用。

19、nginx 变量(了解)

Nginx 同 Apache 和 Lighttpd 等其他 Web 服务器的配置记法不太相同,Nginx的配置文件使用语法的就是一门微型的编程语言。可以类似写程序一般编写配置文件,可操作性很大。既然是编程语言,一般也就少不了“变量”这种东西。

1、nginx变量简介

  • 所有的 Nginx变量在 Nginx 配置文件中引用时都须带上 $ 前缀

  • 在 Nginx 配置中,变量只能存放一种类型的值,有且也只存在一种类型,那就是字符串类型

  • nginx可以使用变量简化配置与提高配置的灵活性,所有的变量值都可以通过这种方式引用:

$变量名

2、nginx 变量的定义和使用

nginx中的变量分为两种,自定义变量与内置预定义变量

1、自定义变量

1、声明变量

可以在sever,http,location等标签中使用set命令(非唯一)声明变量,语法如下

set $变量名 变量值

注意:

  • nginx 中的变量必须都以$开头

  • nginx 的配置文件中所有使用的变量都必须是声明过的,否则 nginx 会无法启动并打印相关异常日志

2、变量的可见性

nginx 变量的一个有趣的特性就是nginx中没一个变量都是全局可见的,而他们又不是全局变量。如下例子

location a/ {
  return 200 $a
}

location b/ {
 set $a hello nginx
 return 200 $a
}

由于变量是全局可见的所以nginx启动不会报错,而第一个location中并不知道$a的具体值因此返回的响应结果为一个空字符串。

在不同层级的标签中声明的变量性的可见性规则如下:

  • location标签中声明的变量中对这个location块可见

  • server标签中声明的变量对server块以及server块中的所有子块可见

  • http标签中声明的变量对http块以及http块中的所有子块可见

3、配置 $foo=hello

server {
    listen 8080;
    server_name  localhost;
    
    location /test {
            set $foo hello;
            echo "foo: $foo";
    }
}

输出

[root@localhost html]# nginx -s reload
[root@localhost html]# curl localhost/test
foo:  hello

4、 输出 $ 符

如果我们想通过 echo 指令直接输出含有“美元符”($)的字符串,那么有没有办法把特殊的 $ 字符给转义掉呢?答案是否定的。不过幸运的是,我们可以绕过这个限制,比如通过不支持“变量插值”的模块配置指令专门构造出取值为 $ 的 Nginx 变量,然后再在 echo 中使用这个变量。看下面这个例子:

http {
    ...
    geo $dollar {
        default "$";
    }
    server {
        ...
       
        location /test-dollar {
            echo "This is a dollar sign: $dollar";
        }
    }
}

输出

[root@localhost html]# nginx -s reload
[root@localhost html]# curl localhost/test-dollar
This is a dollar sign: \$

这里用到了标准模块 ngx_geo 提供的配置指令 geo 来为变量 $dollar 赋予字符串 “$”,这样我们在下面需要使用美元符的地方,就直接引用我们的 $dollar 变量就可以了。

5、 使用大括号插值

在“变量插值”的上下文中,还有一种特殊情况,即当引用的变量名之后紧跟着变量名的构成字符时(比如后跟字母、数字以及下划线),我们就需要使用特别的记法来消除歧义,例如:

server {
    ...
    location /test-brace {
        set $first "hello ";
        echo "${first}world";
    }
}

输出

[root@localhost html]# nginx -s reload
[root@localhost html]# curl localhost/test-brace
hello world

这里,我们在 echo 配置指令的参数值中引用变量 first 的时候,后面紧跟着 world 这个单词,所以如果直接写作 “firstworld” 则 Nginx “变量插值”计算引擎会将之识别为引用了变量 firstworld. 为了解决这个难题,Nginx 的字符串记法支持使用花括号在 之后把变量名围起来,比如这里的 ${first}。

6、变量作用域

set 指令(以及前面提到的 geo 指令)不仅有赋值的功能,它还有创建 Nginx 变量的副作用,即当作为赋值对象的变量尚不存在时,它会自动创建该变量。比如在上面这个例子中,如果 $a 这个变量尚未创建,则 set 指令会自动创建 $a 这个用户变量。如果我们不创建就直接使用它的值,则会报错。

例如

server {
    ...
    location /bad {
        echo $foo;
    }
}

此时 Nginx 服务器会拒绝加载配置:

[emerg] unknown "foo" variable

Nginx 变量的创建和赋值操作发生在全然不同的时间阶段,Nginx 变量的创建只能发生在 Nginx 配置加载的时候,或者说 Nginx 启动的时候,而赋值操作则只会发生在请求实际处理的时候。
这意味着不创建而直接使用变量会导致启动失败,同时也意味着我们无法在请求处理时动态地创建新的 Nginx 变量。

Nginx 变量一旦创建,其变量名的可见范围就是整个 Nginx 配置,甚至可以跨越不同虚拟主机的 server 配置块。我们来看一个例子:

server {
    listen 8080;
    
    location /foo {
        echo "foo = [$foo]";
    }
    
    location /bar {
        set $foo 32;
        echo "foo = [$foo]";
    }
}

输出

[root@localhost html]# curl 'http://localhost/foo'
foo = []

[root@localhost html]# curl 'http://localhost/bar'
foo = [32]

[root@localhost html]# curl 'http://localhost/foo'
foo = []

这里我们在 location /bar 中用 set 指令创建了变量 foo,于是在整个配置文件中这个变量都是可见的,因此我们可以在 location /foo 中直接引用这个变量而不用担心 Nginx 会报错。
从这个例子我们可以看到,set 指令因为是在 location /bar 中使用的,所以赋值操作只会在访问 /bar 的请求中执行。而请求 /foo 接口时,我们总是得到空的 foo值,因为用户变量未赋值就输出的话,得到的便是空字符串。

从这个例子我们可以窥见的另一个重要特性是,Nginx 变量名的可见范围虽然是整个配置,但每个请求都有所有变量的独立副本,或者说都有各变量用来存放值的容器的独立副本,彼此互不干扰。比如前面我们请求了 /bar 接口后,foo 变量被赋予了值 32,但它丝毫不会影响后续对 /foo 接口的请求所对应的 foo 值(它仍然是空的!),因为各个请求都有自己独立的 $foo 变量的副本。

对于 Nginx 新手来说,最常见的错误之一,就是将 Nginx 变量理解成某种在请求之间全局共享的东西,或者说“全局变量”。而事实上,Nginx 变量的生命期是不可能跨越请求边界的。

关于 Nginx 变量的另一个常见误区是认为变量容器的生命期,是与 location 配置块绑定的。其实不然。我们来看一个涉及“内部跳转”的例子:

server {
    listen 8080;

    location /foo {
        set $a hello;
        echo_exec /bar;
    }

    location /bar {
        echo "a = [$a]";
    }
}

输出

[root@localhost html]# curl localhost/foo
a = [hello]

这 里我们在 location /foo 中,使用第三方模块 ngx_echo 提供的 echo_exec 配置指令,发起到 location /bar 的“内部跳转”。所谓“内部跳转”,就是在处理请求的过程中,于服务器内部,从一个 location 跳转到另一个 location 的过程。这不同于利用 HTTP 状态码 301 和 302 所进行的“外部跳转”,因为后者是由 HTTP 客户端配合进行跳转的,而且在客户端,用户可以通过浏览器地址栏这样的界面,看到请求的 URL 地址发生了变化。内部跳转和 Bourne Shell(或 Bash)中的 exec 命令很像,都是“有去无回”。另一个相近的例子是 C 语言中的 goto 语句。

既然是内部跳转,当前正在处理的请求就还是原来那个,只是当前的 location 发生了变化,所以还是原来的那一套 Nginx 变量的容器副本。对应到上例,如果我们请求的是 /foo 这个接口,那么整个工作流程是这样的:先在 location /foo 中通过 set 指令将 a 变量的值赋为字符串 hello,然后通过 echo_exec 指令发起内部跳转,又进入到 location /bar 中,再输出 a 变量的值。因为 a 还是原来的 a,所以我们可以期望得到 hello 这行输出。测试证实了这一点:

但如果我们从客户端直接访问 /bar 接口,就会得到空的 a 变量的值,因为它依赖于 location /foo 来对 a 进行初始化。

从上面这个例子我们看到,一个请求在其处理过程中,即使经历多个不同的 location 配置块,它使用的还是同一套 Nginx 变量的副本。这里,我们也首次涉及到了“内部跳转”这个概念。值得一提的是,标准 ngx_rewrite 模块的 rewrite 配置指令其实也可以发起“内部跳转”,例如上面那个例子用 rewrite 配置指令可以改写成下面这样的形式:

server {

    listen 8080;

    location /foo {
        set $a hello;
        rewrite ^ /bar;
    }

    location /bar {
        echo "a = [$a]";
    }
}

从上面这个例子我们看到,Nginx 变量值容器的生命期是与当前正在处理的请求绑定的,而与 location 无关。

2、内置预定义变量

内置预定义变量即无需声明就可以使用的变量,通常包括一个http请求或响应中一部分内容的值,以下为一些常用的内置预定义变量

变量名 定义
$arg_PARAMETER GET请求中变量名PARAMETER参数的值。
$args 这个变量等于GET请求中的参数。例如,foo=123&bar=blahblah;这个变量只可以被修改
$binary_remote_addr 二进制码形式的客户端地址。
$body_bytes_sent 传送页面的字节数
$content_length 请求头中的Content-length字段。
$content_type 请求头中的Content-Type字段。
$cookie_COOKIE cookie COOKIE的值。
$document_root 当前请求在root指令中指定的值。
$document_uri 与$uri相同。
$host 请求中的主机头(Host)字段,如果请求中的主机头不可用或者空,则为处理请求的server名称(处理请求的server的server_name指令的值)。值为小写,不包含端口。
$hostname 机器名使用 gethostname系统调用的值
$http_HEADER HTTP请求头中的内容,HEADER为HTTP请求中的内容转为小写,-变为_(破折号变为下划线),例如:$http_user_agent(Uaer-Agent的值);
$sent_http_HEADER HTTP响应头中的内容,HEADER为HTTP响应中的内容转为小写,-变为_(破折号变为下划线),例如: $sent_http_cache_control, $sent_http_content_type…;
$is_args 如果$args设置,值为"?",否则为""。
$limit_rate 这个变量可以限制连接速率。
$nginx_version 当前运行的nginx版本号。
$query_string 与$args相同。
$remote_addr 客户端的IP地址。
$remote_port 客户端的端口。
$remote_user 已经经过Auth Basic Module验证的用户名。
$request_filename 当前连接请求的文件路径,由root或alias指令与URI请求生成。
$request_body 这个变量(0.7.58+)包含请求的主要信息。在使用proxy_pass或fastcgi_pass指令的location中比较有意义。
$request_body_file 客户端请求主体信息的临时文件名。
$request_completion 如果请求成功,设为"OK";如果请求未完成或者不是一系列请求中最后一部分则设为空。
$request_method 这个变量是客户端请求的动作,通常为GET或POST。包括0.8.20及之前的版本中,这个变量总为main request中的动作,如果当前请求是一个子请求,并不使用这个当前请求的动作。
$request_uri 这个变量等于包含一些客户端请求参数的原始URI,它无法修改,请查看$uri更改或重写URI。
$scheme 所用的协议,比如http或者是https,比如rewrite ^(.+)$ $scheme://example.com$1 redirect;
$server_addr 服务器地址,在完成一次系统调用后可以确定这个值,如果要绕开系统调用,则必须在listen中指定地址并且使用bind参数。
$server_name 服务器名称。
$server_port 请求到达服务器的端口号。
$server_protocol 请求使用的协议,通常是HTTP/1.0或HTTP/1.1。
$uri 请求中的当前URI(不带请求参数,参数位于args),不同于浏览器传递的args),不同于浏览器传递的args),不同于浏览器传递的request_uri的值,它可以通过内部重定向,或者使用index指令进行修改。不包括协议和主机名,例如/foo/bar.html

Nginx 内建变量最常见的用途就是获取关于请求或响应的各种信息。

1、uri vs request_uri

由 ngx_http_core 模块提供的内建变量 uri,可以用来获取当前请求的 URI(经过解码,并且不含请求参数),
而 request_uri 则用来获取请求最原始的 URI (未经解码,并且包含请求参数)。

location /test-uri {
    echo "uri = $uri";
    echo "request_uri = $request_uri";
}

输出

[root@localhost html]# nginx -s reload
[root@localhost html]# curl localhost/test-uri
uri = /test-uri
request_uri = /test-uri

[root@localhost html]# curl "localhost/test-uri?a=3&b=4"
uri = /test-uri
request_uri = /test-uri?a=3&b=4

[root@localhost html]# curl "localhost/test-uri/hello%20world?a=3&b=4"
uri = /test-uri/hello world
request_uri = /test-uri/hello%20world?a=3&b=4

2、$arg_XXX

另一个特别常用的内建变量其实并不是单独一个变量,而是有无限多变种的一群变量,即名字以 arg_ 开头的所有变量,我们估且称之为 arg_XXX 变量群。
一个例子是 arg_name,这个变量的值是当前请求中名为 name 的参数的值,而且还是未解码的原始形式的值。

location /test-arg {
    echo "name: $arg_name";
    echo "class: $arg_class";
}

输出

[root@localhost html]# nginx -s reload
[root@localhost html]# curl localhost/test-arg
name: 
class:

[root@localhost html]# curl "localhost/test-arg?name=Tom&class=3"
name: Tom
class: 3

[root@localhost html]# curl "localhost/test-arg?name=hello%20world&class=9"
name: hello%20world
class: 9

3、$arg_XXX 不区分大小写

其实 $arg_name 不仅可以匹配 name 参数,也可以匹配 NAME 参数,抑或是 Name,Nginx 会在匹配参数名之前,自动把原始请求中的参数名调整为全部小写的形式。

[root@localhost html]# curl "localhost/test-arg?NAME=Marry"
name: Marry
class:

[root@localhost html]# curl "localhost/test-arg?Name=Jimmy"
name: Jimmy
class:

4、对 uri 解码

如果你想对 URI 参数值中的 %XX 这样的编码序列进行解码,可以使用第三方 ngx_set_misc 模块提供的

location /test-unescape-uri {
    set_unescape_uri $name $arg_name;
    set_unescape_uri $class $arg_class;
    echo "name: $name";
    echo "class: $class";
}

现在我们再看一下效果:

[root@localhost html]# curl "localhost/test-arg?name=hello%20world&class=9"
name: hello world
class: 9

从这个例子我们同时可以看到,这个 set_unescape_uri 指令也像 set 指令那样,拥有自动创建 Nginx 变量的功能。后面我们还会专门介绍到 ngx_set_misc 模块。

像 $arg_XXX 这种类型的变量拥有无穷无尽种可能的名字,所以它们并不对应任何存放值的容器。而且这种变量在 Nginx 核心中是经过特别处理的,第三方 Nginx 模块是不能提供这样充满魔法的内建变量的。

类 似 arg_XXX 的内建变量还有不少,比如用来取 cookie 值的 cookie_XXX 变量群,用来取请求头的 http_XXX 变量群,以及用来取响应头的 sent_http_XXX 变量群。这里就不一一介绍了,感兴趣的读者可以参考 ngx_http_core 模块的官方文档。

20、nginx 监控

1、nginx的基础监控

  • 进程监控

  • 端口监控

注意: 这两个是必须要加在zabbix监控,加触发器有问题及时告警。

web 服务器 nginx 以其高性能与抗并发能力越来越多的被用户使用

作为一款服务器产品,其运行状态是运维密切关注的,因此,对 nginx 的实时监控就必须要关注的了

nginx 提供了 ngx_http_stub_status_module,ngx_http_reqstat_module模块,这个模块提供了基本的监控功能

作为官方企业版的 nginx plus 通过 ngx_http_status_module 提供了更加完善的监控功能: http://demo.nginx.com/status.html

2、监控的主要指标

我们需要对以下主要的指标进行监控:

1、基本活跃指标

Accepts(接受)、Handled(已处理)、Requests(请求数)是一直在增加的计数器。Active(活跃)、Waiting(等待)、Reading(读)、Writing(写)随着请求量而增减。

名称 描述 指标类型
Accepts(接受) NGINX 所接受的客户端连接数 资源: 功能
Handled(已处理) 成功的客户端连接数 资源: 功能
Dropped(已丢弃,计算得出) 丢弃的连接数(接受 - 已处理) 工作:错误*
Requests(请求数) 客户端请求数 工作:吞吐量

NGINX worker 进程接受 OS 的连接请求时 Accepts 计数器增加,而Handled 是当实际的请求得到连接时(通过建立一个新的连接或重新使用一个空闲的)。这两个计数器的值通常都是相同的,如果它们有差别则表明连接被Dropped,往往这是由于资源限制,比如已经达到 NGINX 的worker_connections的限制。

2、每秒请求数 – QPS

按照固定时间间隔采样请求数据,计算出单位时间的请求量可以看到你的 web 服务器的请求情况

通过持续的 QPS 监控,可以立刻发现是否被恶意攻击或对服务的可用性进行评估

虽然当问题发生时,通过 QPS 不能定位到确切问题的位置,但是他却可以在第一时间提醒你环境可能出问题了

3、服务器错误率

通过监控固定时间间隔内的错误代码(4XX代码表示客户端错误,5XX代码表示服务器端错误),可以了解到客户端收到的结果是否是正确的错误率突然的飙升很可能是你的网站漏洞发出的信号

如果你希望通过 access log 分析错误率,那么你需要配置 nginx 的日志模块,让 nginx 将响应码写入访问日志

4、请求处理时间

请求处理时间也可以被记录在 access log 中,通过分析 access log,统计请求的平均响应时间,通过持续观察,可以发现上游服务器的问题

3、指标的收集

介绍了这么多的监控指标,事实上,上面介绍的仅仅是基本的监控指标,针对实际的情况,还有很多指标十分具有监控的必要

那么,怎么去收集这些指标进行监控呢?

通过在编译时加入 nginxngx_http_stub_status_module 模块我们可以实时监控以下基本的指标:

1、nginx Stub Status 监控模块安装

先使用命令查看是否已经安装这个模块:

# -V大写会显示版本号和模块等信息、v小写仅显示版本信息
[root@nginx]#./nginx -V 

# 或用此使用看:
[root@nginx]#nginx -V 2>&1 | grep -o with-http_stub_status_module 

如果已经安装,会在显示的信息中包含 --with-http_stub_status_module信息。如果没有此模块,需要重新安装,编译命令如下:

./configure –with-http_stub_status_module

具体的使用方法是在执行 ./configure 时,指定 --with-http_stub_status_module,然后通过配置:

location /nginx-status {
            stub_status            on;
            access_log             on;
           allow 127.0.0.1;
            deny all;
            #auth_basic              "nginxstatus";
            #auth_basic_user_file  conf/nginxstaus;
}

此处默认只有本地访问,如果远程查看需要加相关的IP或者干脆去掉Deny all即可。加密文件可以使用#htpasswd -c /usr/nginx/conf hxb 命令来创建。配置完成后需要重启Nginx服务。状态配置只能是针对某个Nginx服务。目前Nginx还无法做到针对单个站点进行监控。

2、nginx 状态查看

配置完成后在浏览器中输入http://127.0.0.1/nginx-status 查看(或者用 curl localhost/nginx_status),显示信息如下:

Active connections: 100 
server accepts handled requests
 1075 1064 6253 
Reading: 0 Writing: 5 Waiting: 95 

Accepts(接受)、Handled(已处理)、Requests(请求数)是一直在增加的计数器。Active(活跃)、Waiting(等待)、Reading(读)、Writing(写)随着请求量而增减。

名称 描述 指标类型
Accepts(接受) NGINX 所接受的客户端连接数 资源: 功能
Handled(已处理) 成功的客户端连接数 资源: 功能
Dropped(已丢弃,计算得出) 丢弃的连接数(接受 - 已处理) 工作:错误*
Requests(请求数) 客户端请求数 工作:吞吐量

3、Stub Status 参数说明

active connections – 活跃的连接数量

server accepts handled requests — 总共处理了1075个连接 , 成功创建1064次握手, 总共处理了6253个请求

每个连接有三种状态waiting、reading、writing

reading —读取客户端的Header信息数.这个操作只是读取头部信息,读取完后马上进入writing状态,因此时间很短。

writing — 响应数据到客户端的Header信息数.这个操作不仅读取头部,还要等待服务响应,因此时间比较长。

waiting — 开启keep-alive后等候下一次请求指令的驻留连接.

正常情况下waiting数量是比较多的,并不能说明性能差。反而如果reading+writing数量比较多说明服务并发有问题。
  Nginx基础之错误页面配置/流量控制/访问控制/变量/监控/HTTPS配置/性能优化_第6张图片

名称 描述 是否累加历史数据
Accepts(接受) NGINX 接受的客户端连接数(包括 Handled + Dropped + Waiting)
Handled(已处理) 成功处理的客户端连接数(包含 Waiting 状态连接)
Active(活跃) 当前活跃的客户端连接数
Dropped(已丢弃) 已丢弃连接数(出错)
Requests(请求数) 客户端请求数
Waiting(等待) 正在等待的连接数
Reading(读) 正在执行读操作的连接数
Writing(写) 正在执行写操作的连接数

当用户请求连接Nginx服务器时,accepts计数器会加一。且当服务器处理该连接请求时,handled计数器同样会加一。一般而言,两者的值是相等的,除非达到了某些资源极限(如worker_connection的限制)。

用户连接请求被处理,就会进入 active 状态。如果该连接没有其他 request,则进入 waiting 的子状态;如果有 request,nginx 会读取 request 的 header,计数器 request 加一,进入 reading 的子状态。 reading 状态持续时间非常短,header 被读取后就会进入 writing 状态。事实上,直到服务器将响应结果返回给用户之前,该连接会一直保持 writing 状态。所以说,writing 状态一般会被长时间占用。

一旦 NGINX 成功处理一个连接时,连接会移动到Active状态,在这里对客户端请求进行处理:

Active状态

Waiting: 活跃的连接也可以处于 Waiting 子状态,如果有在此刻没有活跃请求的话。新连接可以绕过这个状态并直接变为到 Reading 状态,最常见的是在使用“accept filter(接受过滤器)” 和 “deferred
accept(延迟接受)”时,在这种情况下,NGINX 不会接收 worker 进程的通知,直到它具有足够的数据才开始响应。如果连接设置为
keep-alive ,那么它在发送响应后将处于等待状态。
Reading: 当接收到请求时,连接离开 Waiting 状态,并且该请求本身使 Reading 状态计数增加。在这种状态下 NGINX 会读取客户端请求首部。请求首部是比较小的,因此这通常是一个快速的操作。
Writing: 请求被读取之后,其使 Writing 状态计数增加,并保持在该状态,直到响应返回给客户端。这意味着,该请求在 Writing 状态时, 一方面 NGINX 等待来自上游系统的结果(系统放在 NGINX “后面”),另外一方面,NGINX
也在同时响应。请求往往会在 Writing 状态花费大量的时间

通常,一个连接在同一时间只接受一个请求。在这种情况下,Active 连接的数目 == Waiting 的连接 + Reading 请求 + Writing 。

怎么利用这些参数?
开源的 Nginx 提供的原始参数中,实时性的会比较有用,如 Active connections、Reading、Writing 以及 Waiting。这些数据能够反映当前 Nginx 的负载情况,方便在服务器出现问题时及时发现问题。而另一些数据由于不是状态量,Nginx 无法计算当前的量值而改做其统计数,如 accepts、handled 和 requests。

对于维护网站人员,accepts、handled 和 requests 的统计值用处是不大的,值得参考的是短时间内这三者数值的增量。这个短时间可以是一秒,如 accepts_per_second、handled_per_second 和 requests_per_second。一个简单的做法就是每秒都去读取这些参数,返回一个和上一秒的差值就行。当然,handled_per_second 替换成 dropped_per_second=accepts_per_second-handled_per_second 就更完美了。

通过这七个参数,就可以从连接到请求全方位的监控起 Nginx 的运行状态。为了方便检测,对每次获取的参数保留下来,然后按时间展现出来。下图展示了 Nginx 在运行时的参考数据。
Nginx基础之错误页面配置/流量控制/访问控制/变量/监控/HTTPS配置/性能优化_第7张图片
nginx折线图

4、Reqstat 模块监控

描述

  • ngx_http_reqstat_module 模块

  • 这个模块计算定义的变量,根据变量值分别统计 nginx 的运行状况。

  • 可以监视的运行状况有:连接数、请求数、各种响应码范围的请求数、输入输出流量、rt、upstream访问等。

  • 可以指定获取所有监控结果或者一部分监控结果。

  • 利用变量添加自定义监控状态。总的监控状态最大个数为50个。

  • 回收过期的监控数据。

  • 设置输出格式

  • 跟踪请求,不受内部跳转的影响

  • 不要使用与响应相关的变量作为条件,比如"$status"

编译
默认编入Tengine,可通过 --without-http_reqstat_module 不编译此模块,或通过–with-http_reqstat_module=shared 编译为so模块。

使用so模块加载的话,请确保其顺序在"ngx_http_lua_module"之后。可以借助"nginx -m"来确认

例子

http {
    req_status_zone server "$host,$server_addr:$server_port" 10M;
    req_status_zone_add_indicator server $limit;
    
    server {
        location /us {
            req_status_show;
            req_status_show_field req_total $limit;
        }

        set $limit 0;

        if ($arg_limit = '1') {
            set $limit 1;
        }

        req_status server;
    }
}
  • 以上例,通过访问/us得到统计结果
  • 每行对应一个server
  • 每行的默认格式

kv,bytes_in,bytes_out,conn_total,req_total,http_2xx,http_3xx,http_4xx,http_5xx,http_other_status,rt,ups_req,ups_rt,ups_tries,http_200,http_206,http_302,http_304,http_403,http_404,http_416,http_499,http_500,http_502,http_503,http_504,http_508,http_other_detail_status,http_ups_4xx,http_ups_5xx

  • kv 计算得到的req_status_zone指令定义变量的值,最大长度可配置,默认104B,超长的部分截断
  • bytes_in 从客户端接收流量总和
  • bytes_out 发送到客户端流量总和
  • conn_total 处理过的连接总数
  • req_total 处理过的总请求数
  • http_2xx 2xx请求的总数
  • http_3xx 3xx请求的总数
  • http_4xx 4xx请求的总数
  • http_5xx 5xx请求的总数
  • http_other_status 其他请求的总数
  • rt rt的总数
  • ups_req 需要访问upstream的请求总数
  • ups_rt 访问upstream的总rt
  • ups_tries upstram总访问次数
  • http_200 200请求的总数
  • http_206 206请求的总数
  • http_302 302请求的总数
  • http_304 304请求的总数
  • http_403 403请求的总数
  • http_404 404请求的总数
  • http_416 416请求的总数
  • http_499 499请求的总数
  • http_500 500请求的总数
  • http_502 502请求的总数
  • http_503 503请求的总数
  • http_504 504请求的总数
  • http_508 508请求的总数
  • http_other_detail_status 非以上13种status code的请求总数
  • http_ups_4xx upstream返回4xx响应的请求总数
  • http_ups_5xx upstream返回5xx响应的请求总数
  • 可以用"req_status_show_field"指令定义输出格式。左侧栏是字段的名字。
  • 注,后续会清理这些状态,因为已经支持了自定义状态。
  • tsar可解析输出结果,具体见https://github.com/alibaba/tsar

指令

Syntax: req_status_zone zone_name value size
Default: none
Context: main

创建统计使用的共享内存。zone_name是共享内存的名称,value用于定义key,支持变量。size是共享内存的大小。

例子:

req_status_zone server "$host,$server_addr:$server_port" 10M;

创建名为“server”的共享内存,大小10M,使用“$host,$server_addr:$server_port”计算key。

  • 注意,如果希望用tsar来监控的话,key的定义中请不要使用逗号。

Syntax: req_status zone_name1 [zone_name2 [zone_name3 […]]]
Default: none
Context: http、srv、loc

开启统计,可以指定同时统计多个目标,每一个zone_name对应一个目标。

Syntax: req_status_show [zone_name1 [zone_name2 […]]]
Default: 所有建立的共享内存目标
Context: loc

按格式返回统计结果。可指定返回部分目标的统计结果。

Syntax: req_status_show_field field_name1 [field_name2 [field_name3 […]]]
Default: all the fields, including user defined fields
Context: loc

定义输出格式。可以使用的字段:内置字段,以上面的名字来表示;自定义字段,用变量表示。
'kv’总是每行的第一个字段。

Syntax: req_status_zone_add_indecator zone_name v a r 1 [ var1 [ var1[var2 […]]
Default: none
Context: http

通过变量增加自定义字段,新增加的字段目前会展现在每行的末尾。

Syntax: req_status_zone_key_length zone_name length
Default: none
Context: http

定义某个共享内存块中key的最大长度,默认值104。key中超出的部分会被截断。

Syntax: req_status_zone_recycle zone_name times seconds
Default: none
Context: http

定义某个共享内存块过期数据的回收。回收在共享内存耗尽时自动开启。只会回收访问频率低于设置值的监控数据。
频率定义为 times / seconds,默认值为10r/min,即

req_status_zone_recycle demo_zone 10 60;
tengine官方说req-statu模块默认安装。但是并没有。而且tengine的req-status模块不能分upstream监控,从github引入第三方模块解决该问题

1. 安装
# cd /usr/local/src/
 # wget "http://nginx.org/download/nginx-1.4.2.tar.gz"
 # tar -xzvf nginx-1.4.2.tar.gz
 # wget https://github.com/zls0424/ngx_req_status/archive/master.zip -O ngx_req_status.zip
 # unzip ngx_req_status.zip
 # cd nginx-1.4.2/
 # patch -p1 < ../ngx_req_status-master/write_filter.patch
 # yum -y install pcre pcre-devel openssl openssl-devel gcc gcc-c++   zlib zlib-devel
 # ./configure --prefix=/usr/local/nginx-1.4.2 --add-module=../ngx_req_status-master
 # make -j2
 # make install
 # useradd nginx    passwd nginx
2. 配置
http {
 req_status_zone server_name $server_name 256k;
 req_status_zone server_addr $server_addr 256k;
 req_status_zone server_url  $server_name$uri 256k;
req_status server_name server_addr server_url;
server {
 server_name www.1000status.com;
 location /req-status {
 req_status_show on;
 }
 }
 }
 
 指令介绍
 req_status_zone
语法: req_status_zone name string size
默认值: None
配置块: http
定义请求状态ZONE,请求按照string分组来排列,例如:
req_status_zone server_url  $server_name$uri 256k;
域名+uri将会形成一条数据,可以看到所有url的带宽,流量,访问数

req_status
语法: req_status zone1[ zone2]
默认值: None
配置块: http, server, location
在location中启用请求状态,你可以指定更多zones。

req_status_show
语法: req_status_show on
默认值: None
配置块: location



./configure --prefix=/usr/local/nginx-1.4.2 --add-module=../ngx_req_status-master --sbin-path=/usr/sbin/nginx  --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/tmp/nginx/client_body  --http-proxy-temp-path=/tmp/nginx/proxy  --http-fastcgi-temp-path=/tmp/nginx/fastcgi --pid-path=/var/run/nginx.pid --lock-path=/var/lock/nginx  --with-http_stub_status_module --with-http_ssl_module   --with-http_gzip_static_module --with-pcre  --group=nginx --user=nginx

5、补充

查看Nginx并发进程数:ps -ef | grep nginx | wc -l

查看Web服务器TCP连接状态:netstat -n | awk ‘/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}’

商业版的 nginx plus 通过他的 ngx_http_status_module 提供了比 nginx 更多的监控指标,可以参看 http://demo.nginx.com/status.html

4、nginx access log 分析

nginx 的 access log 中可以记录很多有价值的信息,通过分析 access log,可以收集到很多指标

python 编写的 linux 工具 ngxtop 就实现了对 access log 的分析功能

三、HTTPS 基本原理

https 介绍

HTTPS(全称:HyperText Transfer Protocol over Secure Socket Layer),其实 HTTPS 并不是一个新鲜协议,Google 很早就开始启用了,初衷是为了保证数据安全。 近些年,Google、Baidu、Facebook 等这样的互联网巨头,不谋而合地开始大力推行 HTTPS, 国内外的大型互联网公司很多也都已经启用了全站 HTTPS,这也是未来互联网发展的趋势。

为鼓励全球网站的 HTTPS 实现,一些互联网公司都提出了自己的要求:

  1. Google 已调整搜索引擎算法,让采用 HTTPS 的网站在搜索中排名更靠前;
  2. 从 2017 年开始,Chrome 浏览器已把采用 HTTP 协议的网站标记为不安全网站;
  3. 苹果要求 2017 年App Store 中的所有应用都必须使用 HTTPS 加密连接;
  4. 当前国内炒的很火热的微信小程序也要求必须使用 HTTPS 协议;
  5. 新一代的 HTTP/2 协议的支持需以 HTTPS 为基础。

等等,因此想必在不久的将来,全网 HTTPS 势在必行。

1、HTTPS 协议介绍

  • HTTP 协议(HyperText Transfer Protocol,超文本传输协议):是客户端浏览器或其他程序与Web服务器之间的应用层通信协议 。

  • HTTPS 协议(HyperText Transfer Protocol over Secure Socket Layer):可以理解为HTTP+SSL/TLS, 即 HTTP 下加入 SSL 层,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL,用于安全的 HTTP 数据传输。
    Nginx基础之错误页面配置/流量控制/访问控制/变量/监控/HTTPS配置/性能优化_第8张图片

  • 如上图所示 HTTPS 相比 HTTP 多了一层 SSL/TLS

    • SSL(Secure Socket Layer,安全套接字层):1994年为 Netscape 所研发,SSL 协议位于 TCP/IP 协议与各种应用层协议之间,为数据通讯提供安全支持。
    • TLS(Transport Layer Security,传输层安全):其前身是 SSL,它最初的几个版本(SSL 1.0、SSL 2.0、SSL 3.0)由网景公司开发,1999年从 3.1 开始被 IETF 标准化并改名,发展至今已经有 TLS 1.0、TLS 1.1、TLS 1.2 三个版本。SSL3.0和TLS1.0由于存在安全漏洞,已经很少被使用到。TLS 1.3 改动会比较大,目前还在草案阶段,目前使用最广泛的是TLS 1.1、TLS 1.2。

2、加密算法

据记载,公元前400年,古希腊人就发明了置换密码;在第二次世界大战期间,德国军方启用了“恩尼格玛”密码机,所以密码学在社会发展中有着广泛的用途。

  1. 对称加密
    有流式、分组两种,加密和解密都是使用的同一个密钥。
    例如:DES、AES-GCM、ChaCha20-Poly1305等

  2. 非对称加密
    加密使用的密钥和解密使用的密钥是不相同的,分别称为:公钥、私钥,公钥和算法都是公开的,私钥是保密的。非对称加密算法性能较低,但是安全性超强,由于其加密特性,非对称加密算法能加密的数据长度也是有限的。

    例如:RSA、DSA、ECDSA、 DH、ECDHE

  3. 哈希算法
    将任意长度的信息转换为较短的固定长度的值,通常其长度要比信息小得多,且算法不可逆。

    例如:MD5、SHA-1、SHA-2、SHA-256 等

  4. 数字签名
    签名就是在信息的后面再加上一段内容(信息经过hash后的值),可以证明信息没有被修改过。hash值一般都会加密后(也就是签名)再和信息一起发送,以保证这个hash值不被修改。

3、HTTPS 原理

1、HTTP 访问过程

Nginx基础之错误页面配置/流量控制/访问控制/变量/监控/HTTPS配置/性能优化_第9张图片

抓包如下:
Nginx基础之错误页面配置/流量控制/访问控制/变量/监控/HTTPS配置/性能优化_第10张图片
如上图所示,HTTP请求过程中,客户端与服务器之间没有任何身份确认的过程,数据全部明文传输,“裸奔”在互联网上,所以很容易遭到黑客的攻击,如下:
Nginx基础之错误页面配置/流量控制/访问控制/变量/监控/HTTPS配置/性能优化_第11张图片
可以看到,客户端发出的请求很容易被黑客截获,如果此时黑客冒充服务器,则其可返回任意信息给客户端,而不被客户端察觉,所以我们经常会听到一词“劫持”,现象如下:

下面两图中,浏览器中填入的是相同的URL,左边是正确响应,而右边则是被劫持后的响应(从貌美如花变成如花。。。)
Nginx基础之错误页面配置/流量控制/访问控制/变量/监控/HTTPS配置/性能优化_第12张图片
所以 HTTP 传输面临的风险有:

  • 窃听风险:黑客可以获知通信内容。
  • 篡改风险:黑客可以修改通信内容。
  • 冒充风险:黑客可以冒充他人身份参与通信。

2、HTTP 向 HTTPS 演化的过程

第一步:为了防止上述现象的发生,人们想到一个办法:对传输的信息加密(即使黑客截获,也无法破解)
Nginx基础之错误页面配置/流量控制/访问控制/变量/监控/HTTPS配置/性能优化_第13张图片
如上图所示,此种方式属于对称加密,双方拥有相同的密钥,信息得到安全传输,但此种方式的缺点是:

(1)不同的客户端、服务器数量庞大,所以双方都需要维护大量的密钥,维护成本很高

(2)因每个客户端、服务器的安全级别不同,密钥极易泄露

第二步:既然使用对称加密时,密钥维护这么繁琐,那我们就用非对称加密试试
Nginx基础之错误页面配置/流量控制/访问控制/变量/监控/HTTPS配置/性能优化_第14张图片
如上图所示,客户端用公钥对请求内容加密,服务器使用私钥对内容解密,反之亦然,但上述过程也存在缺点:

(1)公钥是公开的(也就是黑客也会有公钥),所以第 ④ 步私钥加密的信息,如果被黑客截获,其可以使用公钥进行解密,获取其中的内容

第三步:非对称加密既然也有缺陷,那我们就将对称加密,非对称加密两者结合起来,取其精华、去其糟粕,发挥两者的各自的优势
Nginx基础之错误页面配置/流量控制/访问控制/变量/监控/HTTPS配置/性能优化_第15张图片
如上图所示

(1)第 ③ 步时,客户端说:(咱们后续回话采用对称加密吧,这是对称加密的算法和对称密钥)这段话用公钥进行加密,然后传给服务器

(2)服务器收到信息后,用私钥解密,提取出对称加密算法和对称密钥后,服务器说:(好的)对称密钥加密

(3)后续两者之间信息的传输就可以使用对称加密的方式了

遇到的问题:

(1)客户端如何获得公钥

(2)如何确认服务器是真实的而不是黑客

第四步:获取公钥与确认服务器身份
Nginx基础之错误页面配置/流量控制/访问控制/变量/监控/HTTPS配置/性能优化_第16张图片
1、获取公钥

(1)提供一个下载公钥的地址,回话前让客户端去下载。(缺点:下载地址有可能是假的;客户端每次在回话前都先去下载公钥也很麻烦)

(2)回话开始时,服务器把公钥发给客户端(缺点:黑客冒充服务器,发送给客户端假的公钥)

2、那有木有一种方式既可以安全的获取公钥,又能防止黑客冒充呢? 那就需要用到终极武器了:SSL 证书(申购)
Nginx基础之错误页面配置/流量控制/访问控制/变量/监控/HTTPS配置/性能优化_第17张图片
如上图所示,在第 ② 步时服务器发送了一个SSL证书给客户端,SSL 证书中包含的具体内容有:

(1)证书的发布机构CA

(2)证书的有效期

(3)公钥

(4)证书所有者

(5)签名

………
3、客户端在接受到服务端发来的SSL证书时,会对证书的真伪进行校验,以浏览器为例说明如下:

(1)首先浏览器读取证书中的证书所有者、有效期等信息进行一一校验

(2)浏览器开始查找操作系统中已内置的受信任的证书发布机构CA,与服务器发来的证书中的颁发者CA比对,用于校验证书是否为合法机构颁发

(3)如果找不到,浏览器就会报错,说明服务器发来的证书是不可信任的。

(4)如果找到,那么浏览器就会从操作系统中取出 颁发者CA 的公钥,然后对服务器发来的证书里面的签名进行解密

(5)浏览器使用相同的hash算法计算出服务器发来的证书的hash值,将这个计算的hash值与证书中签名做对比

(6)对比结果一致,则证明服务器发来的证书合法,没有被冒充

(7)此时浏览器就可以读取证书中的公钥,用于后续加密了

4、所以通过发送SSL证书的形式,既解决了公钥获取问题,又解决了黑客冒充问题,一箭双雕,HTTPS加密过程也就此形成

所以相比HTTP,HTTPS 传输更加安全

(1) 所有信息都是加密传播,黑客无法窃听。

(2) 具有校验机制,一旦被篡改,通信双方会立刻发现。

(3) 配备身份证书,防止身份被冒充。

3、HTTPS 总结

综上所述,相比 HTTP 协议,HTTPS 协议增加了很多握手、加密解密等流程,虽然过程很复杂,但其可以保证数据传输的安全。所以在这个互联网膨胀的时代,其中隐藏着各种看不见的危机,为了保证数据的安全,维护网络稳定,建议大家多多推广HTTPS。

HTTPS 缺点:

  1. SSL 证书费用很高,以及其在服务器上的部署、更新维护非常繁琐
  2. HTTPS 降低用户访问速度(多次握手)
  3. 网站改用HTTPS 以后,由HTTP 跳转到 HTTPS 的方式增加了用户访问耗时(多数网站采用302跳转)
  4. HTTPS 涉及到的安全算法会消耗 CPU 资源,需要增加大量机器(https访问过程需要加解密)

4、构建私有的 CA 机构

1、CA 介绍

CA(Certificate Authority)证书颁发机构主要负责证书的颁发、管理以及归档和吊销。证书内包含了拥有证书者的姓名、地址、电子邮件帐号、公钥、证书有效期、发放证书的CA、CA的数字签名等信息。证书主要有三大功能:加密、签名、身份验证。

2、构建私有 CA

1、检查安装 openssl
rpm -qa openssl

如果未安装,安装 openssl

yum install openssl openssl-devel
2、查看配置文件

openssl 配置/etc/pki/tls/openssl.cnf有关CA的配置。如果服务器为证书签署者的身份那么就会用到此配置文件,此配置文件对于证书申请者是无作用的。

####################################################################
[ ca ]
default_ca      = CA_default            # 默认的CA配置;CA_default指向下面配置块

####################################################################
[ CA_default ]

dir             = /etc/pki/CA           # CA的默认工作目录
certs           = $dir/certs            # 认证证书的目录
crl_dir         = $dir/crl              # 证书吊销列表的路径
database        = $dir/index.txt        # 数据库的索引文件


new_certs_dir   = $dir/newcerts         # 新颁发证书的默认路径

certificate     = $dir/cacert.pem       # 此服务认证证书,如果此服务器为根CA那么这里为自颁发证书
serial          = $dir/serial           # 下一个证书的证书编号
crlnumber       = $dir/crlnumber        # 下一个吊销的证书编号
                                        
crl             = $dir/crl.pem          # The current CRL
private_key     = $dir/private/cakey.pem# CA的私钥
RANDFILE        = $dir/private/.rand    # 随机数文件

x509_extensions = usr_cert              # The extentions to add to the cert

name_opt        = ca_default            # 命名方式,以ca_default定义为准
cert_opt        = ca_default            # 证书参数,以ca_default定义为准


default_days    = 365                   # 证书默认有效期
default_crl_days= 30                    # CRl的有效期
default_md      = sha256                # 加密算法
preserve        = no                    # keep passed DN ordering


policy          = policy_match          #policy_match策略生效

# For the CA policy
[ policy_match ]
countryName             = match         #国家;match表示申请者的申请信息必须与此一致
stateOrProvinceName     = match         #州、省
organizationName        = match         #组织名、公司名
organizationalUnitName  = optional      #部门名称;optional表示申请者可以的信息与此可以不一致
commonName              = supplied
emailAddress            = optional

# For the 'anything' policy
# At this point in time, you must list all acceptable 'object'
# types.
[ policy_anything ]                     #由于定义了policy_match策略生效,所以此策略暂未生效
countryName             = optional
stateOrProvinceName     = optional
localityName            = optional
organizationName        = optional
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional
3、根证书服务器目录

根CA服务器:因为只有 CA 服务器的角色,所以用到的目录只有/etc/pki/CA

网站服务器:只是证书申请者的角色,所以用到的目录只有/etc/pki/tls

4、创建所需要的文件
[root@server ~]# cd /etc/pki/CA/
[root@server CA]# ls
certs  crl  newcerts  private
[root@server CA]# touch index.txt        #生成证书索引数据库文件
[root@server CA]# ls
certs  crl  index.txt  newcerts  private
[root@server CA]# echo 01 > serial       #指定第一个颁发证书的序列号
[root@server CA]# ls
certs  crl  index.txt  newcerts  private  serial
5、创建密钥

在根CA服务器上创建密钥,密钥的位置必须为/etc/pki/CA/private/cakey.pem,这个是openssl.cnf中中指定的路径,只要与配置文件中指定的匹配即可。

[root@server CA]# (umask 066; openssl genrsa -out private/cakey.pem 2048)
Generating RSA private key, 2048 bit long modulus
........................................................+++
.........................+++
e is 65537 (0x10001)
6、生成自签名证书

根CA自签名证书,根CA是最顶级的认证机构,没有人能够认证他,所以只能自己认证自己生成自签名证书。

[root@server CA]# openssl req -new -x509 -key /etc/pki/CA/private/cakey.pem -days 7300 -out /etc/pki/CA/cacert.pem -days 7300
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN   
State or Province Name (full name) []:BEIJING      
Locality Name (eg, city) [Default City]:BEIJING
Organization Name (eg, company) [Default Company Ltd]:CA
Organizational Unit Name (eg, section) []:OPT
Common Name (eg, your name or your server's hostname) []:ca.qf.com
Email Address []:
[root@server CA]# ls
cacert.pem  certs  crl  index.txt  newcerts  private  serial
-new: 	生成新证书签署请求
-x509: 	专用于CA生成自签证书
-key: 	生成请求时用到的私钥文件
-days n:	证书的有效期限
-out /PATH/TO/SOMECERTFILE: 	证书的保存路径
7、下载安装证书

/etc/pki/CA/cacert.pem就是生成的自签名证书文件,使用 SZ/xftp工具将他导出到窗口机器中。然后双击安装此证书到受信任的根证书颁发机构
Nginx基础之错误页面配置/流量控制/访问控制/变量/监控/HTTPS配置/性能优化_第18张图片

3、CA 证书申请及签名

1、检查安装 openssl
rpm -qa openssl

如果未安装,安装 openssl

yum install openssl openssl-devel
2、客户端生成私钥文件
[root@node1 ~]# (umask 066; openssl genrsa -out /etc/pki/tls/private/www.qf.com.key 2048)
Generating RSA private key, 2048 bit long modulus
......................+++
....................................................................................+++
e is 65537 (0x10001)
[root@node1 ~]# cd /etc/pki/tls/private
[root@node1 private]# ls
www.qf.com.key
3、客户端用私钥加密生成证书请求
[root@node1 private]# ls ../
cert.pem  certs  misc  openssl.cnf  private  
[root@node1 private]# openssl req -new -key /etc/pki/tls/private/www.qf.com.key -days 365 -out /etc/pki/tls/www.qf.com.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:BEIJING
Locality Name (eg, city) [Default City]:BEIJING
Organization Name (eg, company) [Default Company Ltd]:QF
Organizational Unit Name (eg, section) []:OPT
Common Name (eg, your name or your server's hostname) []:www.qf.com
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
[root@node1 private]# cd ../
[root@node1 tls]# ls
cert.pem  certs  misc  openssl.cnf  private  www.qf.com.csr

CSR(Certificate Signing Request)包含了公钥和名字信息。通常以.csr为后缀,是网站向CA发起认证请求的文件,是中间文件。

在这一命令执行的过程中,系统会要求填写如下信息:

要求添写的内容
Country Name (2 letter code) 使用国际标准组织(ISO)国码格式,填写2个字母的国家代号。中国请填写CN
State or Province Name (full name) 省份,比如填写BeiJing
Locality Name (eg, city) 城市,比如填写BeiJing
Organization Name (eg, company) 组织单位,比如填写公司名称的拼音
Organizational Unit Name (eg, section) 比如填写IT Dept
Common Name (eg, your websites domain name) 城市,比如填写BeiJing
Email Address 邮件地址,可以不填
A challenge password 可以不填
An optional company name 可以不填

最后把生成的请求文件(/etc/pki/tls/www.qf.com.csr)传输给CA ,这里我使用scp命令,通过ssh协议,将该文件传输到CA下的/etc/pki/CA/private/目录

root@node1 tls]# scp www.qf.com.csr 192.168.95.134:/etc/pki/CA/private/
[email protected]'s password: 
www.qf.com.csr                          100%  997   777.2KB/s   00:00  
4、CA 签署证书
[root@server ~]# openssl ca -in /etc/pki/CA/private/www.qf.com.csr -out /etc/pki/CA/certs/www.qf.com.ctr -days 365
Using configuration from /etc/pki/tls/openssl.cnf
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 1 (0x1)
        Validity
            Not Before: Mar 14 13:45:02 2019 GMT
            Not After : Mar 13 13:45:02 2020 GMT
        Subject:
            countryName               = CN
            stateOrProvinceName       = BEIJING
            organizationName          = QF
            organizationalUnitName    = OPT
            commonName                = www.qf.com
        X509v3 extensions:
            X509v3 Basic Constraints: 
                CA:FALSE
            Netscape Comment: 
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier: 
                08:65:70:98:2B:0B:15:D0:74:FE:69:58:05:B8:02:BC:45:D8:23:9B
            X509v3 Authority Key Identifier: 
                keyid:60:6B:BC:F1:A1:01:BF:72:FD:7D:02:A8:BD:15:BE:9C:3B:3E:03:30

Certificate is to be certified until Mar 13 13:45:02 2020 GMT (365 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

证书通常以.crt为后缀,表示证书文件

1、可能遇到的问题
[root@server ~]# openssl openssl ca -in /etc/pki/CA/private/www.qf.com.csr -out /etc/pki/CA/certs/www.qf.com.ctr -days 365
Using configuration from /etc/pki/tls/openssl.cnf
Check that the request matches the signature
Signature ok
The organizationName field needed to be the same in the
CA certificate (CA) and the request (QF)

因为默认使用/etc/pki/tls/openssl.cnf,里面要求其一致,修改organizationName=supplied

修改 /etc/pki/tls/openssl.cnf

# For the CA policy
[ policy_match ]
countryName             = match
stateOrProvinceName     = match
organizationName        = supplied
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional
2、查看生成的证书的信息
[root@server ~]# openssl x509 -in /etc/pki/CA/certs/www.qf.com.ctr -noout -subject
subject= /C=CN/ST=BEIJING/O=QF/OU=OPT/CN=www.qf.com
3、将生成的证书发放给请求客户端
[root@server ~]# scp www.qf.com.ctr [email protected]:/etc/pki/CA/certs/
root@192.168.95.135's password: 
www.qf.com.ctr                            100% 4422     1.3MB/s   00:00  

4、CA吊销证书

1、知道客户端吊销的证书的serial
[root@server ~]#openssl x509 -in /PATH/FROM/CERT_FILE -noout -serial -subject
2、吊销证书

先根据客户提交的serial与subject信息,对比检验是否与index.txt文件中的信息一致;然后

[root@server ~]#openssl ca -revoke /etc/pki/CA/newcerts/SERIAL.pem
3、生成吊销证书的编号

第一次吊销一个证书时才需要执行

[root@server ~]#echo 01 > /etc/pki/CA/crlnumber
4、更新证书吊销列表
[root@server ~]#openssl ca -gencrl -out thisca.crl
5、查看证书吊销列表
[root@server ~]#openssl crl -in /PATH/FROM/CRL_FILE.crl -noout -text

5、nginx HTTPS 部署实战

  1. 申请证书与认证
  2. 证书下载与配置
  3. 问题分析与总结

申请证书与认证

要搭建https服务首先需有SSL证书,证书通常是在第三方申请,在阿里云的安全服务中有SSL证书这一项,可以在里面申请免费的证书;

也可以在自己电脑中生成,虽然也能完成加密,但是浏览器是不认可的,因此最好还是去第三方申请

1、证书申请

阿里云提供免费的证书,不需要人工审核,用来做测试是非常不错的选择,申请地址如下URL。

https://common-buy.aliyun.com/?spm=5176.2020520163.cas.1.1aa12b7aWWn20O&commodityCode=cas#/buy

免费型的证书隐藏的比较深,想要申请免费证书需要先选择 1个域名->Symantec->免费型 ,所以读者这里需要注意一下,如下图参考。
Nginx基础之错误页面配置/流量控制/访问控制/变量/监控/HTTPS配置/性能优化_第19张图片
选择之后,一直点击下一步,便可购买完成,免费购买证书之后笔者需要回到证书控制台,在控制台有一个补全信息的链接地址,需要通过此地址补充申请人的联系信息,参考下图填写
Nginx基础之错误页面配置/流量控制/访问控制/变量/监控/HTTPS配置/性能优化_第20张图片

2、域名验证

补全个人信息之后,还需要给阿里云验证当前域名是属于本人的,验证方式有两种,第一种是通过dns解析认证,第二种是通过上传验证文件认证,这里采用的是验证文件认证,首先需要下载文件,如下图
Nginx基础之错误页面配置/流量控制/访问控制/变量/监控/HTTPS配置/性能优化_第21张图片
在下载验证文件完成之后,笔者需要把文件放到服务器中去,这里提供一条复制命令

[root@web ~]#scp ~/Downloads/fileauth.txt  [email protected]:~/

将验证文件复制到服务器之后,还需要将验证文件放到站点对应目录,参考命令如下:

[root@web ~]#mkdir -p /website/.well-known/pki-validation  &&  cp  fileauth.txt  /website/.well-known/pki-validation/

现在要验证文件放置的位置是否正确,通过两种方式进行了验证,分别是手动验证,和阿里云验证。

1、手动验证

手动验证的目的是首先确保文件位置放置是否正确,可以通过访问站点的url是否成功进行判断,比如笔者可以访问如下URL,如果返回如果页面能够正常打开,并且可以看到某些值,则代表配置成功。

http://www.qf.com/.well-known/pki-validation/fileauth.txt
2、通过阿里云来验证

在确保文件放置正确之后,关键的是能让阿里云能访问到,阿里云这里提供了一个检查配置的功能,在下载验证文件页面,有一个检测配置的链接,单击之后便可进行检查,如下图。
Nginx基础之错误页面配置/流量控制/访问控制/变量/监控/HTTPS配置/性能优化_第22张图片
当点击 检查配置 之后,如果阿里云能够正常访问,则会在左侧给出提示,现在可以返回证书列表,在列表中可以看到当前状态为审核中,如下图
在这里插入图片描述
审核因为不需要人为干预,所以很快就能下发证书,下发证书的时间大约是2分钟左右。

证书下载与配置

1、证书下载

证书签发之后,可以在列表中可以看到状态栏中为 已签发 ,同时操作栏可以下载以及查看详情等,如下图所示
Nginx基础之错误页面配置/流量控制/访问控制/变量/监控/HTTPS配置/性能优化_第23张图片
点击下载后,会跳转到下载详情页面,在下载详情页可以选择自己相对应的web服务,比如使用nginx,当选择nginx之后,下方还会很贴心的提示如何配置,下载nginx配置文件。

下载配置文件之后,需要将其解压,解压之后可以看见里面包含了两个证书文件

xxx.key

xxx.pem

接着需要把这两个证书文件给复制到服务器当中去,首先需要在服务器创建对应的文件夹,参考命令如下

[root@web ~]#cd  /usr/local/nginx/conf/  &&  mkdir cert    #此命令在服务器执行

在服务器创建完成对应文件夹之后,执行命令将证书文件复制到服务器中,参考命令如下:

[root@web ~]#scp ~/Downloads/214905423420461/*  [email protected]:/usr/local/nginx/conf/cert
2、证书配置

证书复制完成之后,可以对nginx配置文件进行更改,使用vim命令编辑nginx配置文件,参考命令如下:

[root@web ~]#vim /usr/local/nginx/conf/nginx.conf

在vim界面把之前http的配置部分复制一份,复制之后修改监听的端口(listen)为443,并在其后面添加ssl的信息,参考配置如下:

 	listen 443;
    ssl on;
    ssl_certificate   cert/214905423420461.pem;
    ssl_certificate_key  cert/214905423420461.key;
    ssl_session_timeout 5m;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
3、重启Nginx

修改配置文件之后,需要测试nginx配置文件是否正确

[root@web ~]#nginx -t 

当nginx如果没有出现error相关信息,基本配置没有问题,下面是我的nginx返回结果:

nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful

nginx 配置没有问题之后,笔者需要重启nginx让其生效,参考命令如下

[root@web ~]#nginx -s reload
4、检验效果

现在所有该做的工作都做好了,笔者可以通过浏览器来访问可以正常访问,打开如下URL。

https://www.xxx.com

浏览器地址栏显示如下图所示
在这里插入图片描述
如果看到浏览器,展示安全,并且显示绿色就说明大功告成了

6、nginx 性能优化

当我需要进行性能优化时,说明我们服务器无法满足日益增长的业务。性能优化是一个比较大的课题,需要从以下几个方面进行探讨

  • 当前系统结构瓶颈
  • 了解业务模式
  • 性能与安全

1、当前系统结构瓶颈

首先需要了解的是当前系统瓶颈,用的是什么,跑的是什么业务。里面的服务是什么样子,每个服务最大支持多少并发。比如针对nginx而言,我们处理静态资源效率最高的瓶颈是多大?能支持多少qps访问请求?怎么得出系统当前的结构瓶颈?

可以通过查看当前cpu负荷,内存使用率,进程使用率来做简单判断。还可以通过操作系统的一些工具来判断当前系统性能瓶颈,如分析对应的日志,查看请求数量。也可以通过nginx http_stub_status_module模块来查看对应的连接数,总握手次数,总请求数。也可以对线上进行压力测试,来了解当前的系统能性能,并发数,做好性能评估。

2、了解业务模式

虽然我们是在做性能优化,但还是要熟悉业务,最终目的都是为业务服务的。我们要了解每一个接口业务类型是什么样的业务,比如电子商务抢购模式,这种情况平时流量会很小,但是到了抢购时间,流量一下子就会猛涨。也要了解系统层级结构,每一层在中间层做的是代理还是动静分离,还是后台进行直接服务。需要我们对业务接入层和系统层次要有一个梳理

3、性能与安全

性能与安全也是一个需要考虑的因素,往往大家注重性能忽略安全或注重安全又忽略性能。比如说我们在设计防火墙时,如果规则过于全面肯定会对性能方面有影响。如果对性能过于注重在安全方面肯定会留下很大隐患。所以大家要评估好两者的关系,把握好两者的孰重孰轻,以及整体的相关性。权衡好对应的点。

4、系统与nginx性能优化

大家对相关的系统瓶颈及现状有了一定的了解之后,就可以根据影响性能方面做一个全体的评估和优化。

  • 网络(网络流量、是否有丢包,网络的稳定性都会影响用户请求)
  • 系统(系统负载、饱和、内存使用率、系统的稳定性、硬件磁盘是否有损坏)
  • 服务(连接优化、内核性能优化、http服务请求优化都可以在nginx中根据业务来进行设置)
  • 程序(接口性能、处理请求速度、每个程序的执行效率)
  • 数据库、底层服务

上面列举出来每一级都会有关联,也会影响整体性能,这里主要关注的是nginx服务这一层。

1、文件句柄

在linux/unix操作系统中一切皆文件,我们的设备是文件,文件是文件,文件夹也是文件。当我们用户每发起一次请求,就会产生一个文件句柄。文件句柄可以简单的理解为文件句柄就是一个索引。文件句柄就会随着请求量的增多,进程调用频繁增加,那么产生的文件句柄也就会越多。

系统默认对文件句柄是有限制的,不可能会让一个进程无限制的调用句柄。因为系统资源是有限的,所以我们需要限制每一个服务能够使用多大的文件句柄。操作系统默认使用的文件句柄是1024个句柄。

2、设置方式
  • 系统全局性修改
  • 用户局部性修改
  • 进程局部性修改
3、系统全局性修该和用户局部性修改
[root@server ~]#vim /etc/security/limits.conf

在文件最下面找到

#*               soft    core            0
#*               hard    rss             10000
#@student        hard    nproc           20
#@faculty        soft    nproc           20
#@faculty        hard    nproc           50
#ftp             hard    nproc           0
#@student        -       maxlogins       4

#root只是针对root这个用户来限制,soft只是发提醒,操作系统不会强制限制,一般的站点设置为一万左右就ok了
root soft nofile 65535
root hard nofile 65535
# *代表通配符 所有的用户
*    soft nofile 25535
*    hard nofile 25535

可以看到root*,root代表是root用户,*代表的是所有用户,后面的数字就是文件句柄大小。大家可以根据个人业务来进行设置。

4、进程局部性修改
[root@server ~]#vim /etc/nginx/nginx.conf
user  nginx;
worker_processes  1;  

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

worker_rlimit_nofile 65535; #进程限制

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

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

    access_log  /var/log/nginx/access.log  main;

    sendfile        on; 
    #tcp_nopush     on; 

    keepalive_timeout  65; 

    #gzip  on; 

    include /etc/nginx/conf.d/*.conf;
}

worker_rlimit_nofile 是在进程上面进行限制。

5、cpu的亲和配置

cpu的亲和能够使nginx对于不同的work工作进程绑定到不同的cpu上面去。就能够减少在work间不断切换cpu,把进程通常不会在处理器之间频繁迁移,进程迁移的频率小,来减少性能损耗。[nginx 亲和配置](

查看物理cpu

[root@server ~]#cat /proc/cpuinfo|grep "physical id"|sort |uniq|wc -l

查看cpu核心数

[root@server ~]#cat /proc/cpuinfo|grep "cpu cores"|uniq

查看cpu使用率

[root@server ~]#top  回车后按 1
6、配置worker_processes
[root@server ~]#vim /etc/nginx/nginx.conf

将刚才查看到自己cpu * cpu核心就是worker_processes

worker_processes 2; #根据自己cpu核心数配置
7、cpu亲和配置

假如小菜的配置是2cpu,每个cpu是8核。配置如下

worker_processes 16;
  1010101010101010 0101010101010101;

配置完成后可以通过下面命令查看nginx进程配置在哪个核上

[root@server ~]#ps -eo pid,args,psr |grep [n]ginx

在nginx 1.9版本之后,就帮我们自动绑定了cpu;

worker_cpu_affinity auto;

5、nginx通用配置优化

[root@server ~]#vim /etc/nginx/nginx.conf
#将nginx进程设置为普通用户,为了安全考虑
user nginx; 

#当前启动的worker进程,官方建议是与系统核心数一直
worker_processes 2;
#方式一, 第一个work进程绑定第一个cpu核心,第二个work进程绑定到第二个cpu核心,依次内推 直到弟16个
#wokrer_cpu_affinity 0000000000000000 0000000000000001 0000000000000010 0000000000000100 ... 1000000000000000

#方式二,当 worker_processes 2 时,表明 第一work进程可以绑定第 2 4 6 8 10 12 14 16 核心,那么第二work进程就绑定 奇数核心
#worker_cpu_affinity 1010101010101010 0101010101010101;

#方式三,就是自动分配绑定
worker_cpu_affinity auto;

#日志配置成warn
error_log /var/log/nginx/error.log warn; 
pid /var/run/nginx.pid;

#针对 nginx 句柄的文件限制
worker_rlimit_nofile 35535;
#事件模型
events {
    #使用epoll内核模型
    user epoll;
    #每一个进程可以处理多少个连接,如果是多核可以将连接数调高 worker_processes * 1024
    worker_connections 10240;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    charset utf-8;  #设置字符集

    #设置日志输出格式,根据自己的情况设置
    log_format  main  '$http_user_agent' '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" '
                      '"$args" "$request_uri"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;   #对静态资源的处理比较有效
    #tcp_nopush     on;   #如果做静态资源服务器可以打开
    #tcp_nodeny     on;   #当nginx做动态的服务时可以选择打开

    keepalive_timeout  65; 

    ########
    #Gzip module
    gzip  on;    #文件压缩默认可以打开
    gzip_disable "MSIE [1-6]\."; #对于有些浏览器不能识别压缩,需要过滤如ie6
    gzip_http_version 1.1;

    include /etc/nginx/conf.d/*.conf;
}
#查看 核心绑定的nginx work进程
[root@server ~]#ps -eo pid,args,psr | grep [n]ginx

6、ab接口压力测试工具

ab是Apache超文本传输协议(HTTP)的性能测试工具。其设计意图是描绘当前所安装的Apache的执行性能,主要是显示你安装的Apache每秒可以处理多少个请求。

# 安装工具
[root@server ~]#yum install httpd-tools

# 使用
[root@server ~]#ab -n 2000 -c 2 http://127.0.0.1/index.html
-n 总的请求数
-c 并发数
-k 是否开启长连接
1、参数选项
-n:即requests,用于指定压力测试总共的执行次数
-c:即concurrency,用于指定的并发数
-t:即timelimit,等待响应的最大时间(单位:秒)
-b:即windowsize,TCP发送/接收的缓冲大小(单位:字节)
-p:即postfile,发送POST请求时需要上传的文件,此外还必须设置-T参数
-u:即putfile,发送PUT请求时需要上传的文件,此外还必须设置-T参数
-T:即content-type,用于设置Content-Type请求头信息,例如:application/x-www-form-urlencoded,默认值为text/plain
-v:即verbosity,指定打印帮助信息的冗余级别
-w:以HTML表格形式打印结果
-i:使用HEAD请求代替GET请求
-x:插入字符串作为table标签的属性
-y:插入字符串作为tr标签的属性
-z:插入字符串作为td标签的属性
-C:添加cookie信息,例如:"Apache=1234"(可以重复该参数选项以添加多个)
-H:添加任意的请求头,例如:"Accept-Encoding: gzip",请求头将会添加在现有的多个请求头之后(可以重复该参数选项以添加多个)
-A:添加一个基本的网络认证信息,用户名和密码之间用英文冒号隔开
-P:添加一个基本的代理认证信息,用户名和密码之间用英文冒号隔开
-X:指定使用的和端口号,例如:"126.10.10.3:88"
-V:打印版本号并退出
-k:使用HTTP的KeepAlive特性
-d:不显示百分比
-S:不显示预估和警告信息
-g:输出结果信息到gnuplot格式的文件中
-e:输出结果信息到CSV格式的文件中
-r:指定接收到错误信息时不退出程序
-H:显示用法信息,其实就是ab -help
2、内容解释
Server Software:        nginx/1.10.2 (服务器软件名称及版本信息)
Server Hostname:        192.168.1.106(服务器主机名)
Server Port:            80 (服务器端口)

Document Path:          /index1.html. (供测试的URL路径)
Document Length:        3721 bytes (供测试的URL返回的文档大小)

Concurrency Level:      1000 (并发数)
Time taken for tests:   2.327 seconds (压力测试消耗的总时间)
Complete requests:      5000 (的总次数)
Failed requests:        688 (失败的请求数)
Write errors:           0 (网络连接写入错误数)
Total transferred:      17402975 bytes (传输的总数据量)
HTML transferred:       16275725 bytes (HTML文档的总数据量)
Requests per second:    2148.98 [#/sec] (mean) (平均每秒的请求数) 这个是非常重要的参数数值,服务器的吞吐量 
Time per request:       465.338 [ms] (mean) (所有并发用户(这里是1000)都请求一次的平均时间)
Time  request:       	0.247 [ms] (mean, across all concurrent requests) (单个用户请求一次的平均时间)
Transfer rate:          7304.41 [Kbytes/sec] received 每秒获取的数据长度 (传输速率,单位:KB/s)
...
Percentage of the requests served within a certain time (ms)
  50%    347  ## 50%的请求在347ms内返回 
  66%    401  ## 60%的请求在401ms内返回 
  75%    431
  80%    516
  90%    600
  95%    846
  98%   1571
  99%   1593
 100%   1619 (longest request)
3、示例演示
[root@server ~]#ab -n 50 -c 20 http://walidream.com/sub_module

输出内容

Server Software:        nginx/1.14.1
Server Hostname:        walidream.com
Server Port:            80

Document Path:          /sub_module
Document Length:        169 bytes

Concurrency Level:      20
Time taken for tests:   0.005 seconds
Complete requests:      50
Failed requests:        0
Write errors:           0
Non-2xx responses:      50
Total transferred:      14900 bytes
HTML transferred:       8450 bytes
Requests per second:    9746.59 [#/sec] (mean)
Time per request:       2.052 [ms] (mean)
Time per request:       0.103 [ms] (mean, across all concurrent requests)
Transfer rate:          2836.41 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       1
Processing:     1    1   0.3      1       2
Waiting:        0    1   0.2      1       1
Total:          1    2   0.3      2       2

Percentage of the requests served within a certain time (ms)
  50%      2
  66%      2
  75%      2
  80%      2
  90%      2
  95%      2
  98%      2
  99%      2
 100%      2 (longest request)
5、注意事项

● 测试机与被测试机要分开

● 不要对线上的服务器做压力测试

● 观察测试工具ab所在机器,以及被测试的前端机的CPU、内存、网络等都不超过最高限度的75%

6、ab性能指标
1、吞吐率(Requests per second)

服务器并发处理能力的量化描述,单位是reqs/s,指的是在某个并发用户数下单位时间内处理的请求数。某个并发用户数下单位时间内能处理的最大请求数,称之为最大吞吐率。记住:吞吐率是基于并发用户数的。这句话代表了两个含义:

● 吞吐率和并发用户数相关

● 不同的并发用户数下,吞吐率一般是不同的

计算公式:总请求数/处理完成这些请求数所花费的时间,即

Request per second=Complete requests/Time taken for tests

必须要说明的是,这个数值表示当前机器的整体性能,值越大越好
必须要说明的是,这个数值表示当前机器的整体性能,值越大越好

2、并发连接数(The number of concurrent connections)

并发连接数指的是某个时刻服务器所接受的请求数目,简单的讲,就是一个会话。

3、并发用户数(Concurrency Level)

要注意区分这个概念和并发连接数之间的区别,一个用户可能同时会产生多个会话,也即连接数。在HTTP/1.1下,IE7支持两个并发连接,IE8支持6个并发连接,FireFox3支持4个并发连接,所以相应的,我们的并发用户数就得除以这个基数。

4.用户平均请求等待时间(Time per request)

计算公式:处理完成所有请求数所花费的时间/(总请求数/并发用户数),即:

Time per request=Time taken for tests/(Complete requests/Concurrency Level)
5.服务器平均请求等待时间(Time per request:across all concurrent requests)

计算公式:处理完成所有请求数所花费的时间/总请求数,即:

Time taken for/testsComplete requests

可以看到,它是吞吐率的倒数。同时,它也等于用户平均请求等待时间/并发用户数,即

Time per request/Concurrency Level

7、cfssl 部署 (了解)

1、下载cfssl工具

[root@server ~]#wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
[root@server ~]#chmod +x cfssl_linux-amd64
[root@server ~]#sudo mv cfssl_linux-amd64 /root/local/bin/cfssl
 
[root@server ~]#wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
[root@server ~]#chmod +x cfssljson_linux-amd64
[root@server ~]#sudo mv cfssljson_linux-amd64 /root/local/bin/cfssljson
 
[root@server ~]#wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
[root@server ~]#chmod +x cfssl-certinfo_linux-amd64
[root@server ~]#sudo mv cfssl-certinfo_linux-amd64 /root/local/bin/cfssl-certinfo
 
[root@server ~]#export PATH=/root/local/bin:$PATH

2、生成默认的配置文件和证书签名请求文件

[root@server ~]#cfssl print-defaults config > ca-config.json
[root@server ~]#cfssl print-defaults csr > ca-csr.json
1、查看并修改CA 配置文件
[root@server ~]#cat ca-config.json 
{
    "signing": {
        "default": {
            "expiry": "9999h"
        },
        "profiles": {
            "www": {
                "expiry": "9999h",
                "usages": [
                    "signing",
                    "key encipherment",
                    "server auth"
                ]
            },
            "client": {
                "expiry": "9999h",
                "usages": [
                    "signing",
                    "key encipherment",
                    "client auth"
                ]
            }
        }
    }
}
  • ca-config.json:可以定义多个 profiles,分别指定不同的过期时间、使用场景等参数;后续在签名证书时使用某个 profile;

  • signing:表示该证书可用于签名其它证书;生成的 ca.pem 证书中 CA=TRUE

  • server auth:表示 client 可以用该 CA 对 server 提供的证书进行验证;

  • client auth:表示 server 可以用该 CA 对 client 提供的证书进行验证;

2、查看并修改 CA 证书签名请求
{
  "CN": "registry.test.com",
  "hosts": [
    "127.0.0.1",
    "172.16.160.38",
    "registry.test.com"
  ],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "BeiJing",
      "L": "BeiJing",
      "O": "k8s",
      "OU": "System"
    }
  ]
}
  • “CN”:Common Name,kube-apiserver 从证书中提取该字段作为请求的用户名 (User Name);浏览器使用该字段验证网站是否合法;

  • “O”:Organization,kube-apiserver 从证书中提取该字段作为请求用户所属的组 (Group);

3、生成 CA 证书和私钥
[root@server ~]#cfssl gencert -initca ca-csr.json | cfssljson -bare ca    #重新执行
[root@server ~]#ls ca*
ca-config.json  ca.csr  ca-csr.json  ca-key.pem  ca.pem
4、分发证书

3、校验证书

1、使用 openssl 命令校验证书
[root@server ~]#openssl x509  -noout -text -in  kubernetes.pem
...
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=CN, ST=BeiJing, L=BeiJing, O=k8s, OU=System, CN=Kubernetes
        Validity
            Not Before: Apr  5 05:36:00 2017 GMT
            Not After : Apr  5 05:36:00 2018 GMT
        Subject: C=CN, ST=BeiJing, L=BeiJing, O=k8s, OU=System, CN=kubernetes
...
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage:
                TLS Web Server Authentication, TLS Web Client Authentication
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Subject Key Identifier:
                DD:52:04:43:10:13:A9:29:24:17:3A:0E:D7:14:DB:36:F8:6C:E0:E0
            X509v3 Authority Key Identifier:
                keyid:44:04:3B:60:BD:69:78:14:68:AF:A0:41:13:F6:17:07:13:63:58:CD
 
            X509v3 Subject Alternative Name:
                DNS:kubernetes, DNS:kubernetes.default, DNS:kubernetes.default.svc, DNS:kubernetes.default.svc.cluster, DNS:kubernetes.default.svc.cluster.local, IP Address:127.0.0.1, IP Address:10.64.3.7, IP Address:10.254.0.1
...
 
 
+ 确认 `Issuer` 字段的内容和 `ca-csr.json` 一致;
+ 确认 `Subject` 字段的内容和 `kubernetes-csr.json` 一致;
+ 确认 `X509v3 Subject Alternative Name` 字段的内容和 `kubernetes-csr.json` 一致;
+ 确认 `X509v3 Key Usage、Extended Key Usage` 字段的内容和 `ca-config.json``kubernetes` profile 一致;
2、使用 cfssl-certinfo 命令校验证书
[root@server ~]#cfssl-certinfo -cert kubernetes.pem
...
{
  "subject": {
    "common_name": "kubernetes",
    "country": "CN",
    "organization": "k8s",
    "organizational_unit": "System",
    "locality": "BeiJing",
    "province": "BeiJing",
    "names": [
      "CN",
      "BeiJing",
      "BeiJing",
      "k8s",
      "System",
      "kubernetes"
    ]
  },
  "issuer": {
    "common_name": "Kubernetes",
    "country": "CN",
    "organization": "k8s",
    "organizational_unit": "System",
    "locality": "BeiJing",
    "province": "BeiJing",
    "names": [
      "CN",
      "BeiJing",
      "BeiJing",
      "k8s",
      "System",
      "Kubernetes"
    ]
  },
  "serial_number": "174360492872423263473151971632292895707129022309",
  "sans": [
    "kubernetes",
    "kubernetes.default",
    "kubernetes.default.svc",
    "kubernetes.default.svc.cluster",
    "kubernetes.default.svc.cluster.local",
    "127.0.0.1",
    "10.64.3.7",
    "10.64.3.8",
    "10.66.3.86",
    "10.254.0.1"
  ],
  "not_before": "2017-04-05T05:36:00Z",
  "not_after": "2018-04-05T05:36:00Z",
  "sigalg": "SHA256WithRSA",
...
3、使用浏览器验证

导入证书

​ ca.pem改名为ca.crt。将正式导入浏览器。

构建https服务

[root@server ~]#cd /root/ssl_test
[root@server ~]#cat > http-server.js <
var https = require('https');
var fs = require('fs');
 
var options = {
    key: fs.readFileSync('./keys/app-key.pem'),
    cert: fs.readFileSync('./keys/app.pem')
};
 
https.createServer(options, function (req, res) {
    res.writeHead(200);
    res.end('hello world');
}).listen(8000);
EOF
 
[root@server ~]#yum install nodejs -y
[root@server ~]#npm install https -g
[root@server ~]#node http-server.js

修改hosts文件添加

172.16.160.28 www.test.com

在浏览器访问https://www.test.com:8000 发现网站显示为安全

4、附加内容

数字证书中主题(Subject)中字段的含义

  • 一般的数字证书产品的主题通常含有如下字段:
字段名 字段值
公用名称 (Common Name) 简称:CN 字段,对于 SSL 证书,一般为网站域名;而对于代码签名证书则为申请单位名称;而对于客户端证书则为证书申请者的姓名;
单位名称 (Organization Name) 简称:O 字段,对于 SSL 证书,一般为网站域名;而对于代码签名证书则为申请单位名称;而对于客户端单位证书则为证书申请者所在单位名称;
  • 证书申请单位所在地
字段名 字段值
所在城市 (Locality) 简称:L 字段
所在省份 (State/Provice) 简称:S 字段
所在国家 (Country) 简称:C 字段,只能是国家字母缩写,如中国:CN
  • 其他一些字段
字段名 字段值
电子邮件 (Email) 简称:E 字段
多个姓名字段 简称:G 字段
介绍 Description 字段
电话号码: Phone 字段,格式要求 + 国家区号 城市区号 电话号码,如: +86 732 88888888
地址: STREET 字段
邮政编码: PostalCode 字段
显示其他内容 简称:OU 字段

例子:

[root@server ca]#cat ca-config.json 
{
    "signing": {
        "default": {
            "expiry": "9999h"
        },
        "profiles": {
            "www": {
                "expiry": "9999h",
                "usages": [
                    "signing",
                    "key encipherment",
                    "server auth"
                ]
            },
            "client": {
                "expiry": "9999h",
                "usages": [
                    "signing",
                    "key encipherment",
                    "client auth"
                ]
            }
        }
    }
}
 
[root@server ca]#cat ca-csr.json 
{
  "CN": "registry.test.com",
  "hosts": [
    "127.0.0.1",
    "172.16.160.38",
    "registry.test.com"
  ],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "BeiJing",
      "L": "BeiJing",
      "O": "k8s",
      "OU": "System"
    }
  ]
}
 
[root@server ca]#ll
总用量 8
-rw-r--r-- 1 root root 568 11月 14 15:59 ca-config.json
-rw-r--r-- 1 root root 289 11月 14 16:02 ca-csr.json
 
[root@dev ca]# cfssl gencert -initca ca-csr.json | cfssljson -bare ca
2018/11/14 16:05:01 [INFO] generating a new CA key and certificate from CSR
2018/11/14 16:05:01 [INFO] generate received request
2018/11/14 16:05:01 [INFO] received CSR
2018/11/14 16:05:01 [INFO] generating key: rsa-2048
2018/11/14 16:05:01 [INFO] encoded CSR
2018/11/14 16:05:01 [INFO] signed certificate with serial number 303515642193399207794287652931621857332460556169
 
[root@server ca]#ll
总用量 20
-rw-r--r-- 1 root root  568 11月 14 15:59 ca-config.json
-rw-r--r-- 1 root root 1082 11月 14 16:05 ca.csr
-rw-r--r-- 1 root root  289 11月 14 16:02 ca-csr.json
-rw------- 1 root root 1679 11月 14 16:05 ca-key.pem
-rw-r--r-- 1 root root 1379 11月 14 16:05 ca.pem
 
 
[root@server ~]#openssl x509  -noout -text -in ca.pem
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            35:2a:1c:b2:f6:1a:f3:82:38:50:05:8c:fb:65:ef:9e:89:74:8f:89
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=CN, ST=BeiJing, L=BeiJing, O=k8s, OU=System, CN=harbor
        Validity
            Not Before: Nov 14 08:00:00 2018 GMT
            Not After : Nov 13 08:00:00 2023 GMT
        Subject: C=CN, ST=BeiJing, L=BeiJing, O=k8s, OU=System, CN=harbor
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:b7:2e:6a:52:f4:d2:34:8b:5e:3f:95:5d:c8:b0:
                    85:9a:1b:ef:c5:0f:1b:94:b9:94:12:fe:fa:66:0d:
                    8c:67:b8:9e:82:30:fc:e1:42:94:6e:00:fb:c0:fd:
                    84:be:65:2c:e4:8f:f1:f1:93:e5:ae:8e:5b:74:7a:
                    d5:94:25:9c:01:76:f9:96:4e:02:b9:27:a2:44:e0:
                    da:b3:f3:09:82:5c:9f:26:a6:26:54:35:15:e6:a6:
                    7a:4b:14:99:07:9d:e3:c3:b8:bd:3f:b6:76:53:05:
                    82:02:bb:e2:61:21:23:5b:3b:23:4c:08:eb:a7:51:
                    00:fb:01:5f:b7:f8:b9:67:5b:a1:99:19:23:42:7a:
                    d2:22:0a:11:01:1d:75:34:9e:25:9c:c8:9f:31:d7:
                    f5:f3:98:14:b8:c4:07:f3:5a:a1:fa:96:bd:0f:b3:
                    dc:13:5b:8e:03:e8:66:3b:b5:bd:8d:08:ee:61:c2:
                    4f:78:dc:9a:ee:37:f8:87:6b:5f:e3:87:ae:91:b0:
                    8c:c9:40:51:44:cb:57:47:23:f1:2d:34:af:0f:5f:
                    42:89:14:ac:de:73:d4:32:54:c2:de:99:38:96:d4:
                    b8:de:f3:df:5c:a5:55:54:8f:a1:b7:fa:42:8b:d9:
                    fe:2d:14:1f:d5:62:d9:c7:c1:4d:55:41:3b:a9:d3:
                    0d:2d
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: critical
                Certificate Sign, CRL Sign
            X509v3 Basic Constraints: critical
                CA:TRUE, pathlen:2
            X509v3 Subject Key Identifier: 
                15:1F:81:A2:AC:41:18:DA:DD:19:36:03:61:18:7B:EF:3D:94:10:AE
            X509v3 Authority Key Identifier: 
                keyid:15:1F:81:A2:AC:41:18:DA:DD:19:36:03:61:18:7B:EF:3D:94:10:AE
 
            X509v3 Subject Alternative Name: 
                IP Address:127.0.0.1, IP Address:172.16.160.38
    Signature Algorithm: sha256WithRSAEncryption
         62:41:3c:40:6d:91:29:d2:0b:6d:ce:08:a1:e4:47:64:0a:66:
         0e:c0:55:eb:c4:6b:30:6d:79:51:b4:97:8c:02:1e:15:ba:0f:
         84:ce:2a:3c:c7:86:29:3c:1f:55:35:a1:da:df:70:5d:58:93:
         45:24:c4:20:4d:c1:c7:bb:83:8d:52:0c:7d:43:e2:7c:5b:00:
         5d:57:5a:b5:bf:d0:56:5a:57:32:ca:fc:29:59:23:ab:5e:1e:
         0e:9b:f9:f6:8d:e8:e4:c6:cb:e6:fe:9f:e3:cd:55:2e:7b:35:
         1e:bc:80:0f:ba:d8:66:ae:43:19:bf:d1:bb:81:17:d6:4a:3b:
         01:ba:d4:28:da:3f:19:63:82:72:6f:df:7a:b4:bc:d4:cf:a9:
         b1:fc:a6:c7:c1:5d:9b:09:2e:72:2a:d4:18:ed:f4:3d:97:1e:
         e6:43:81:5c:eb:40:2c:f9:aa:6f:90:16:70:46:77:52:09:64:
         43:83:00:0c:44:59:de:17:65:7b:7e:3d:51:df:54:6e:bb:80:
         cb:22:13:e2:20:80:91:f8:3f:5e:83:70:32:68:ad:ad:7e:4a:
         15:32:45:a7:a5:c4:ed:1c:d4:e4:cc:38:ac:8a:9d:d1:bb:4e:
         1c:21:17:56:a2:a0:f9:39:f3:73:e4:96:00:ac:98:93:f3:80:
         96:9d:b5:97
[root@dev ca]#

如果出现

[root@server ~]#docker login registry.test.com
Username (admin): admin
Password: 
Error response from daemon: Get https://registry.mayocase.com/v1/users/: x509: certificate signed by unknown authority

检查下目录/etc/docker/certs.d/registry.test.com下是否有ca.crt文件,可能需要重启docker

[root@server ~]#cp ca.pem /etc/docker/certs.d/registry.test.com/ca.crt
[root@server ~]#systemctl restart docker

修改harbor证书后操作:

[root@server ~]#cd /data/harbor    #一定要在此目录下运行以下命令。
[root@server ~]#ll
总用量 878344
drwxr-xr-x 4 root root        35 7月  31 2017 common
-rw-r--r-- 1 root root      1988 7月  31 2017 docker-compose.notary.yml
-rw-r--r-- 1 root root      3155 7月  31 2017 docker-compose.yml
-rw-r--r-- 1 root root      4304 7月  31 2017 harbor_1_1_0_template
-rw-r--r-- 1 root root      4178 7月  31 2017 harbor.cfg
-rw-r--r-- 1 root root      1082 7月  31 2017 harbor.csr
-rw-r--r-- 1 root root       288 7月  31 2017 harbor-csr.json
-rw-r--r-- 1 root root 448963966 7月  31 2017 harbor.v1.1.1.tar.gz
-rw-r--r-- 1 root root 450041094 7月  31 2017 harbor.v1.1.2.tar.gz
-rwxr-xr-x 1 root root      5169 7月  31 2017 install.sh
-rw-r--r-- 1 root root    337600 7月  31 2017 LICENSE
-rw-r--r-- 1 root root       472 7月  31 2017 NOTICE
-rwxr-xr-x 1 root root     16522 7月  31 2017 prepare
-rwxr-xr-x 1 root root      4550 7月  31 2017 upgrade 
# 停止 harbor
[root@server harbor]# docker-compose down -v        #多运行几次直到所有docker都删除
# 修改配置
[root@server harbor]# vim harbor.cfg
# 更修改的配置更新到 docker-compose.yml 文件
[root@server harbor]# ./prepare
# 启动 harbor
[root@server harbor]#  docker-compose up -d

8、特例: https 为什么慢,把nginx 跑到 qat 卡上

Intel QAT 助力 Nginx 压缩处理

1、什么是Intel® QAT?

Intel® QuickAssist Technology是Intel®公司提供的一种高性能数据安全和压缩的加速方案。该方案利用QAT芯片分担对称/非对称加密计算,DEFLATE无损压缩等大计算量的任务,来降低CPU使用率并提高整体平台性能。该方案可以主板芯片,独立的PCI-E加速卡或者SOC三种方式部署。

QAT支持硬件加速Deflate无损压缩算法,在处理海量数据时,QAT在不增加CPU开销的前提下,通过压缩来减少需要传输和存盘的数据量,从而减少了网络带宽和磁盘读写的开销,最终提高了整体的系统性能。 例如,在Web Serer上使用QAT硬件加速压缩处理,可将CPU从繁重的压缩计算中解放出来,以处理更多的连接请求。

2、什么是Nginx Web Server

Nginx(发音同engine x)是一款使用异步框架的高性能Web服务器,相较于Apache、lighttpd等其他Web Server,Nginx具有占有内存少,稳定性高等优势。根据Netcraft 2018年一月的Web Server市场调查报告, Nginx的装机率达25.39%,位列Web Server市场第三,并在持续增长中[1]。

Nginx中的GZIP模块实现了对HTTP压缩的支持,该模块通过调用Zlib库实现对网页内容进行Deflate压缩。由于使用软件实现无损压缩,需要消耗大量CPU运算时间进行压缩运算。

然而,在大并发流量的网站接入层的Nginx需要处理相当多的业务,包括https连接建立,安防攻击,流量镜像,链路追踪等等。使得CPU进行HTTP压缩处理成为Web Server最主要的CPU开销,进而限制了网站支持最大并发连接数。根据客户提供的接入层流量模型分析来看, GZIP 单个模块 CPU 消耗占比达到 15%-20% 左右,且占比呈上升趋势。所以,若能使用加速Nginx的网页压缩处理,可以极大的提高网站性能。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iBGF86Oi-1592399674118)(assets/1-1.jpg)]

3、Zlib-SHIM API

Zlib作为广泛部署的软件压缩库,提供Deflate压缩的软件实现,被包括Nginx在内的广大应用程序所采用。Intel® QuickAssist Technology提供了与Zlib类似接口的Zlib-SHIM 软件库来适配上层应用,减少了应用迁移的开发量。该库提供了与Zlib一致的Deflate API,只需对源代码做少量修改,并将原有应用与Zlib-SHIM编译链接,就能使用QuickAssit提供的硬件加速功能。

Zlib-SHIM库实现了DeflateInit,DeflateInit2,Deflate,DeflateEnd等常用API并支持Stateful和Stateless压缩,可以替代Zlib的绝大部分功能。

Zlib-SHIM提供了Deflate API同步模式接口(调用程序阻塞在Deflate API上,直到压缩任务完成),而其内部实现调用了异步模式API,即在CPU上运行的QAT驱动程序向QAT协处理器提交了一个数据压缩请求后即返回,期间使用Polling 接口定期检查压缩请求是否完成,等到QAT硬件完成压缩处理后通过回调函数通知CPU端的应用程序进行下一步操作。这样的设计, 在不影响上层应用程序原有设计的前提下,实现了高并发场景中CPU和QAT的协同工作:CPU专注于网络链接处理而QAT处理复杂的压缩计算, 各司其职,最终提高了系统整体性能。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jaDbTTHK-1592399674126)(assets/2-1552557277602.png)]Zlib-SHIM 层次图

4、Zlib-SHIM工作原理

采用这种异步模式API实现对外的同步接口,在实现上有三种方法:Direct Polling,Indirect Polling Spinning和Indirect Polling Semaphore模式。

使用Direct Polling模式时,Deflate调用者会在当前线程直接调用Polling接口,若压缩结果还没有返回则休眠一段时间后再检查,直到压缩成功后Deflate 调用才返回。Direct Polling模式下CPU开销小,但是单个Request从发出到返回结果延迟较长,只有在多进程多线程高并发模式下才能充分发挥QAT的压缩性能。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Yh8xtUpC-1592399674126)(assets/3.png)]Direct polling 模式流程图

Indirect Polling模式,是通过创建一个轮询线程定期调用Polling接口来检查压缩请求在QAT 协处理器中的执行状态,轮询线程一旦发现有请求执行完毕就通过回调函数(Callback Function)通知CPU端程序进行后续处理。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XkwCXwdA-1592399674128)(assets/4-1.png)]

Indirect pooling模式时序图

根据回调通知方式的不同,Indirect Polling模式又可细分为Spinning模式和Semaphore模式:

Spinning模式中,Deflate函数调用线程定期轮询与回调函数共享的任务完成标志,若尚未完成则主动休眠,若已完成则进行后续处理。

Semaphore模式中,Deflate调用线程通过互斥锁来隔离与轮询线程共享的任务完成标志的访问操作,若任务尚未完成则Deflate调用线程休眠,一旦任务完成,轮询线程中的回调函数会通过信号量唤醒调用线程进行后续处理。

采用Indirect Polling模式无论Deflate调用数目多少都需要启动轮询线程,在压缩请求数不大的情况下增加了CPU的Polling开销,但是当压缩任务作为CPU的主要任务时可以减少不必要的Polling调用,提高CPU的使用率。

Nginx为了实现高性能的高并发处理能采用了单进程单线程异步工作模式,如果使用Indirect Polling模式,就需要在每个Nginx Worker进程中创建一个轮询线程 (Polling Thread), 从而增加了线程间切换的开销和共享数据的互斥的操作, 所以在Nginx和Zlib-SHIM集成中,我们使用了Direct Polling Mode。

5、USDM优化

USDM是QAT为了优化内存使用效率而提供的用户态内存管理工具。由于QAT和CPU之前需要频繁高速的交换数据,使用传统的Memory Copy方式不仅效率低而且消耗CPU资源,所以QAT支持DMA方式进行数据传输,CPU只需分配好拥有物理连续内存的输入地址和输出地址,QAT会自动完成的从该地址的输入读取或输出写回的操作。QAT Driver中的USDM模块,利用了Linux 内核提供的Huge-Page特性来获得物理地址连续内存并使用SLAB算法进行内存管理。

对于每一个新分配的Huge-Page,USDM会对应地在Devfs中新建一个临时文件,并通过mmap将临时文件描述符与新申请到的Huge-Page关联上,当USDM发现该Huge-Page上所有内存块均已释放,并不需将其留作缓存时,就关闭该临时文件以释放Huge-Page。当Zlib-SHIM运行过程中需要使用连续的内存时,就使用USDM Alloc接口从内存池中申请连续物理地址的内存, 并在发送压缩请求时将申请到的连续内存地址作为参数传递给QAT。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ihKd2D5t-1592399674129)(assets/5-1.jpg)]USDM DMA传输

6、测试结果

基于以上设计的Zlib-SHIM可以很方便的替换原有Zlib库,使得调用者可以方便的利用QAT进行压缩加速。 在实际应用中, 客户就是将Zlib-SHIM与基于Nginx定制的Web Server进行集成,在接入层的性能优化上取得了理想的效果。

客户的Web Server运行在Intel® Xeon® CPU上(CPU型号:Intel® Xeon® CPU E5-2650 v2 @ 2.60GHz 32核 内核:2.6.32 Zlib版本:zlib-1.2.8 QAT驱动版本:intel-qatOOT40052 ),在相同网络流量条件下,未开启QAT加速的CPU平均使用率为48%左右,而开启QAT加速后CPU平均使用率为41%左右。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vDsJsoHO-1592399674130)(assets/6-1.jpg)]CPU使用率对比[2]

相同条件下,开启QAT加速后系统load平均值为12.09,关闭QAT加速时系统load平均值为14.22,如下图所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XlpD74vD-1592399674130)(assets/7-1.jpg)]系统load对比[2]

综合以上数据,Web Server在QPS 10K的压力下,使用QAT加速后可以节省CPU 15%左右,且Gzip基本上完全卸载、随着其占比变高,优化效果将越好。

7、总结

拥有和Zlib相同API接口的Zlib-SHIM可以很方便的与上层应用集成,利用QAT的硬件加速性能。此外,为了最大限度的发挥QAT的新能,Intel还提供了使用专有API的QATzip软件库,相应的Nginx module也在开发中,相信不久的将来集成QATzip的Web Server能够提供更好的性能。

性能测试中使用的软件和工作负荷可能仅在英特尔微处理器上进行了性能优化。诸如SYSmark和MobileMark等测试均系基于特定计算机系统、硬件、软件、操作系统及功能。上述任何要素的变动都有可能导致测试结果的变化。请参考其他信息及性能测试(包括结合其他产品使用时的运行性能)以对目标产品进行全面评估。

你可能感兴趣的:(Nginx基础)