安全开发运维必备的Nginx代理Web服务器性能优化与安全加固配置

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了安全开发运维必备的Nginx代理Web服务器性能优化与安全加固配置相关的知识,希望对你有一定的参考价值。

参考技术A

为了更好的指导部署与测试艺术升系统nginx网站服务器高性能同时下安全稳定运行,需要对nginx服务进行调优与加固;

本次进行Nginx服务调优加固主要从以下几个部分:

本文档仅供内部使用,禁止外传,帮助研发人员,运维人员对系统长期稳定的运行提供技术文档参考。

Nginx是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP服务器。Nginx作为负载均衡服务器, Nginx 既可以在内部直接支持 Rails 和 php 程序对外进行服务,也可以支持作为 HTTP代理服务器对外进行服务。

Nginx版本选择:

项目结构:



Nginx文档帮助: http://nginx.org/en/docs/
Nginx首页地址目录: /usr/share/nginx/html
Nginx配置文件:



localtion 请求匹配的url实是一个正则表达式:

Nginx 匹配判断表达式:

例如,匹配末尾为如下后缀的静态并判断是否存在该文件, 如不存在则404。



查看可用模块编译参数:http://nginx.org/en/docs/configure.html



http_gzip模块
开启gzip压缩输出(常常是大于1kb的静态文件),减少网络传输;



http_fastcgi_module模块
nginx可以用来请求路由到FastCGI服务器运行应用程序由各种框架和PHP编程语言等。可以开启FastCGI的缓存功能以及将静态资源进行剥离,从而提高性能。



keepalive模块
长连接对性能有很大的影响,通过减少CPU和网络开销需要开启或关闭连接;



http_ssl_module模块
Nginx开启支持Https协议的SSL模块

Linux内核参数部分默认值不适合高并发,Linux内核调优,主要涉及到网络和文件系统、内存等的优化,

下面是我常用的内核调优配置:



文件描述符
文件描述符是操作系统资源,用于表示连接、打开的文件,以及其他信息。NGINX 每个连接可以使用两个文件描述符。
例如如果NGINX充当代理时,通常一个文件描述符表示客户端连接,另一个连接到代理服务器,如果开启了HTTP 保持连接,这个比例会更低(译注:为什么更低呢)。

对于有大量连接服务的系统,下面的设置可能需要调整一下:



精简模块:Nginx由于不断添加新的功能,附带的模块也越来越多,建议一般常用的服务器软件使用源码编译安装管理;

(1) 减小Nginx编译后的文件大小



(2) 指定GCC编译参数
修改GCC编译参数提高编译优化级别稳妥起见采用 -O2 这也是大多数软件编译推荐的优化级别。

GCC编译参数优化 [可选项] 总共提供了5级编译优化级别:



常用编译参数:



缓存和压缩与限制可以提高性能
NGINX的一些额外功能可用于提高Web应用的性能,调优的时候web应用不需要关掉但值得一提,因为它们的影响可能很重要。

简单示例:



1) 永久重定向

例如,配置 http 向 https 跳转 (永久)



nginx配置文件指令优化一览表



描述:Nginx因为安全配置不合适导致的安全问题,Nginx的默认配置中存在一些安全问题,例如版本号信息泄露、未配置使用SSL协议等。
对Nginx进行安全配置可以有效的防范一些常见安全问题,按照基线标准做好安全配置能够减少安全事件的发生,保证采用Nginx服务器系统应用安全运行;

Nginx安全配置项:

温馨提示: 在修改相应的源代码文件后需重新编译。

设置成功后验证:



应配置非root低权限用户来运行nginx服务,设置如下建立Nginx用户组和用户,采用user指令指运行用户

加固方法:



我们应该为提供的站点配置Secure Sockets Layer Protocol (SSL协议),配置其是为了数据传输的安全,SSL依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密。



不应使用不安全SSLv2、SSLv3协议即以下和存在脆弱性的加密套件(ciphers), 我们应该使用较新的TLS协议也应该优于旧的,并使用安全的加密套件。



HTTP Referrer Spam是垃圾信息发送者用来提高他们正在尝试推广的网站的互联网搜索引擎排名一种技术,如果他们的垃圾信息链接显示在访问日志中,并且这些日志被搜索引擎扫描,则会对网站排名产生不利影响
加固方法:



当恶意攻击者采用扫描器进行扫描时候利用use-agent判断是否是常用的工具扫描以及特定的版本,是则返回错误或者重定向;



Nginx支持webdav,虽然默认情况下不会编译。如果使用webdav,则应该在Nginx策略中禁用此规则。
加固方法: dav_methods 应设置为off



当访问一个特制的URL时,如"../nginx.status",stub_status模块提供一个简短的Nginx服务器状态摘要,大多数情况下不应启用此模块。
加固方法:nginx.conf文件中stub_status不应设置为:on



如果在浏览器中出现Nginx自动生成的错误消息,默认情况下会包含Nginx的版本号,这些信息可以被攻击者用来帮助他们发现服务器的潜在漏洞
加固方法: 关闭"Server"响应头中输出的Nginx版本号将server_tokens应设置为:off



client_body_timeout设置请求体(request body)的读超时时间。仅当在一次readstep中,没有得到请求体,就会设为超时。超时后Nginx返回HTTP状态码408(Request timed out)。
加固方法:nginx.conf文件中client_body_timeout应设置为:10



client_header_timeout设置等待client发送一个请求头的超时时间(例如:GET / HTTP/1.1)。仅当在一次read中没有收到请求头,才会设为超时。超时后Nginx返回HTTP状态码408(Request timed out)。

加固方法:nginx.conf文件中client_header_timeout应设置为:10



keepalive_timeout设置与client的keep-alive连接超时时间。服务器将会在这个时间后关闭连接。

加固方法:nginx.conf文件中keepalive_timeout应设置为:55



send_timeout设置客户端的响应超时时间。这个设置不会用于整个转发器,而是在两次客户端读取操作之间。如果在这段时间内,客户端没有读取任何数据,Nginx就会关闭连接。

加固方法:nginx.conf文件中send_timeout应设置为:10



GET和POST是Internet上最常用的方法。Web服务器方法在RFC 2616中定义禁用不需要实现的可用方法。

加固方法:



limit_zone 配置项限制来自客户端的同时连接数。通过此模块可以从一个地址限制分配会话的同时连接数量或特殊情况。

加固方法:nginx.conf文件中limit_zone应设置为:slimits $binary_remote_addr 5m



该配置项控制一个会话同时连接的最大数量,即限制来自单个IP地址的连接数量。

加固方法:nginx.conf 文件中 limit_conn 应设置为: slimits 5



加固方法:





加固方法:



解决办法:





描述后端获取Proxy后的真实Client的IP获取需要安装--with-http_realip_module,然后后端程序采用JAVA(request.getAttribute("X-Real-IP"))进行获取;



描述: 如果要使用geoip地区选择,我们需要再nginx编译时加入 --with-http_geoip_module 编译参数。



描述: 为了防止外部站点引用我们的静态资源,我们需要设置那些域名可以访问我们的静态资源。



描述: 下面收集了Web服务中常规的安全响应头, 它可以保证不受到某些攻击,建议在指定的 server 代码块进行配置。



描述: 为了防止某些未备案的域名或者恶意镜像站域名绑定到我们服务器上, 导致服务器被警告关停,将会对业务或者SEO排名以及企业形象造成影响,我们可以通过如下方式进行防范。

执行结果:



描述: 有时你的网站可能只需要被某一IP或者IP段的地址请求访问,那么非白名单中的地址访问将被阻止访问, 我们可以如下配置;



常用nginx配置文件解释:

(1) 阿里巴巴提供的Concat或者Google的PageSpeed模块实现这个合并文件的功能。



(2) PHP-FPM的优化
如果您高负载网站使用PHP-FPM管理FastCGI对于PHP-FPM的优化非常重要



(3) 配置Resin on Linux或者Windows为我们可以打开 resin-3.1.9/bin/httpd.sh 在不影响其他代码的地方加入:-Dhttps.protocols=TLSv1.2, 例如

原文地址: https://blog.weiyigeek.top/2019/9-2-122.html

运维高手二:nginx高性能优化配置实战

本文我们聊一下关于Nginx配置优化的内容,相信对于Nginx你一定并不陌生,它是一款轻量级的开源Web服务及代理程序。在Nginx出现之前市场上主流两款Web服务,一款是Windows系统上的IIS,另外一款是Linux系统上的Apache。而在Nginx诞生后,因其轻量化、支持高并发等特性,逐渐蚕食了这两款Web服务的市场份额。目前国内大量企业早已广泛的使用 Nginx。既然 Nginx 使用这么广泛,那么我们在运维工作中如何对其进行优化和配置便成了重中之重。

你在阅读本文之前,我们需要提前掌握一些基础知识,包括:

  • 熟悉Linux 的基础操作;

  • 了解 Nginx 安装和基础配置;

  • 对 HTTP 请求过程有一定了解。

Nginx 的优化主要分为两部分,一部分是基础配置优化,另外一部分是缓存配置优化。

基础配置优化主要包括:

  • CPU亲和性优化;

  • Nginx 模型优化;

  • Nginx 传输方式优化;

  • Nginx 文件压缩优化。

缓存配置优化主要包括:

  • 浏览器缓存优化

  • 代理缓存优化

  • HTTPS SSL 缓存优化

  • KV 服务缓存优化

基础配置优化

CPU 亲和性

所谓的 CPU 亲和性是做什么的呢?现在的CPU通常是多核的,并可以通过超线程来虚拟更多核数 ,那亲和力就是为多核 CPU 需做到让 Nginx 服务充分的配合使用,从而提高性能。Nginx运行时会启用 1 个 master 进程及多个 worker 进程,worker 进程负责处理请求,如果 worker 进程在多核 CPU中发生频繁的调度就会损耗性能。在这种情况下,我们希望减少这种频繁调度,让每一个 Nginx 的worker 线程都能够固定到具体的 CPU核心上,所以就需要配置 Nginx 的 CPU 亲和性来解决这个问题。

由于 Nginx CPU亲和性配置本身有多套配置方案,这里推荐你直接将配置项设置成auto(worker_cpu_affinity),即采用了 Nginx 推荐的 CPU 绑核策略方式。另外的一个方式是手动绑定,将 worker 线程数量与 CPU 核心数一一绑定方式设置。我们设置成auto Nginx 会自动识别并按照推荐策略来分配worker 线程和 CPU。

如图所示,我们看到 CPU 的核心有 8 个,即CPU0~CPU7,如果我们设置成 auto 后,那么Nginx会将 8 个 worker 线程一对一地按照推荐策略绑定到 CPU 核心上,这样避免 CPU 频繁对 worker 线程进行调度,从而降低 CPU 损耗。

IO 流事件模型

我们经常可以在 Nginx 下面看到的 events 配置模块中默认设置了 use epoll,表示 Nginx 使用 epoll 这个 IO 流事件模型,那为什么Nginx 会选择使用 epoll 呢?这是因为 epoll有以下这些得天独厚的优势。

首先,Linux 系统下一切皆文件,比如我们打开一个设备,它便会产生一个文件描述符。在产生一个进程时,这个进程便需要一个进程描述符,这个进程描述符也是一个文件。所以在 Nginx 处理请求的时候,每一个请求都会产生处理请求的描述符。

其次,在 Nginx 处理大规模请求的时候,为了提高并发效率需要采用异步非阻塞模型,这又和 epoll有什么关系呢?epoll 本身是以异步非阻塞模型来处理请求流中的事件流。

这里还需要注意一点,并不是所有的 Linux 操作系统都可以使用epoll,它是在 kernel 2.6 版本以后提出的,早期内核使用的 selectpoll 模型,select 模型比 epoll 模型性能要低很多,有经验的运维同学一定深有体会。

通过上面的背景铺垫,我们再来详细介绍下epoll 相比于 select 模型具备的优势:

  • epoll 处理事件流模型是线程安全的;

  • epoll 跟 select 模型相比调用 fd 文件描述符时使用了 mmap 共享用户和内核的部分空间,提高了效率;

  • epoll 是基于事件驱动的,相比 select 需要扫描整个文件描述符的相关状态,epoll 基于事件驱动避免频繁扫描文件描述符,可以直接调用callback 回调函数,效率更高;

  • 取消了select模型里面单个进程能够监视的文件描述符的数量存在的最大限制(1024),如果你有使用过早期的Apache版本的,它使用的select模型,当请求超过1000以后就会出现延迟或者请求错误,而改用 Nginx 的话性能会得到明显的改善。

另外补充下,在 events{} 配置中还涉及一个优化的地方就是 worker_connections,这个也是在events 里面来进行设置的,通过上面的学习我们知道了 worker 线程作用,那每一个 work线程所支持的连接是有限的,这里会默认设置成 1024,而我们在处理高并发的场景时,单个 worker 线程设置成 1024 的话往往偏低,这里建议你将worker_connections 调大一些,你可以参考实际业务所需 Nginx 处理最大峰值来调大这个设置值。

零拷贝

第三个基础配置优化是零拷贝,所谓零拷贝的配置是在 Nginx 中的 HTTP 配置模块中添加一个sendfile on 配置项,它便是一个零拷贝,所谓零拷贝并不代表不拷贝了,而是说它做到了文件的内核态到用户态的零拷贝。

运维高手二:nginx高性能优化配置实战

如图所示,我们先来看下没有零拷贝时文件传输是什么样子的?首先 Nginx 在处理文件时,会将文件传入操作系统内核态的 Buffer Cache,然后传递到操作系统上层的用户态,经用户态的 Buffer Cache 再传回内核态中,最后通过 Socket 将文件转发出去。

这个时候你会发现一个问题,对于静态文件并不需要流转到用户态中,直接通过内核态效率更高,所以这时我们就需要在 Nginx 中开启 sendfile on,这样静态文件就可以通过红色的路径在内核态中完成转发,而不用再去绕道用户态,提高了效率。

文件压缩

我们希望做到 Nginx 服务端往客户端发送的数据越小,占用的延迟越低用户体验便会越好。所以往往在代理或 Nginx 中会设置文件压缩,我们主要通过gzip 方式进行设置,主要的设置项如下:

  • gzip on 负责打开后端的压缩功能;

  • gzip_buffer 16 8k 表示设置 Nginx 在处理文件压缩时的内存空间;

  • gzip_comp_level 6 表示 Nginx 在处理压缩时的压缩等级,通常等级越高它的压缩比就越大,但并不是说压缩比越大越好,还是需要根据实际情况来选择合适的压缩比,压缩比太大影响性能,压缩比太小起不到应有的效果,一般来说推荐你设置成 6 就比较合适;

  • gzip_http_version 1.1 表示只对 HTTP 1.1 版本的协议进行压缩;

  • gzip_proxied any 代表 Nginx 作为反向代理时依据后端服务器时返回信息设置一些 gzip 压缩策略;

  • gzip_vary on 表示是否发送Vary:

    Accept_Encoding 响应头字段,实现通知接收方服务端作了gzip 压缩;

  • application/vnd.ms-fontobject image/x-icon; gip 压缩类型;

  • gzip_disable “msie6”; 关闭 IE6 的压缩。

最后这两项表示设置 zip 的压缩类型及是否关闭客户端使用 IE6 浏览器请求过来的压缩,以上就是对文件压缩的典型配置,你可以根据具体情况做一些细节上的调整。

缓存配置优化

缓存优化

我们先讲解缓存优化配置,基于缓存元素存放的位置,再对我们所需要讲的缓存作一个分类。

如果缓存的元素在客户端的,那么主要有浏览器缓存和 HTTPS 缓存,你可别认为缓存文件是在客户端,这两部分缓存效果都可以 Nginx 这种代理来进行设置并作主要优化。

另外一个种类代理端的缓存(也就是缓存文件存放在代理服务的节点中),那Nginx 作为反向代理服务的时候,可以支持代理缓存设置。

最后一个种类是将缓存文件放入后台服务(通过后台服务中程序逻辑来实现),例如我们可以将一部分数据通过此方式缓存,比如将用户最长查看的数据(网站中登录状态、连接数等)缓存到Memcache、Redis 中,避免直接请求关系型数据库或其他服务,因为效用效率更高所以可以降低后端的延迟,也减少请求对数据库的依赖度,从而整个网站的性能也会有很大的提升。

只考虑缓存最优的话,我有三点经验可以分享给你:

  1. 缓存越靠前越好,通常情况下整个网站的元素内容越靠前越好,也就是说能放在客户端的就放在客户端,而不要放到后端去频繁请求。

  2. 缓存的数据越多越好,也就是能在本层级缓存的数据越多,就越可以减少对后端的请求。

  3. 缓存的命中率越高越好,如果设置了很多缓存,但命中率不高,同样还是会造成穿透到后端访问,此时还需要考虑将缓存的命中率设置的越高,这时观察指标,会发现缓存效果越优。

通常而言,一个网站如果做了缓存优化可以比没做缓存优化的性能提升几倍以上。

浏览器缓存

第一个就是浏览器缓存,浏览器缓存通常是缓存到客户端(如:浏览器、客户端app),这就是浏览器缓存。

对于浏览器这部分缓存数据,我们通常可以把静态元素,比如用户请求的图片、CSS 、JS 等元素缓存到客户端。这种缓存可以通过 Nginx配置中的expires 配置项进行设置,expires 后面可以加具体的时间,也可以加对应的特定意义的数值,比如 -1 表示永久缓存,max 设置最大周期缓存(默认缓存周期为 10 年),需要做具体的时间的设置可以写入具体的时间周期,比如一个小时或是一天。

HTTPS 配置优化

当前我们很多网站通常在开启HTTPS ,当开启https后客户端访问服务端打开一次浏览器,通过https方式会比 HTTP 请求握手会要增加很多次从而延迟也增加了。这时就需要考虑 HTTPS 是否有更好的优化方案来减少客户端和服务端请求。

如图中是一个https请求过程,实际在进行HTTPS 请求之前的需要进行TCP 的三次握手过程,而这里我只是描述 HTTPS 的建立连接过程,客户端发送hello 报文,服务端发送证书,客户端进行加密,服务端验证加密。这时开始进行服务端与客户端的传输。我们看到整个 HTTPS 建立连接增加了部分的证书加密的协商。

多次的连接对于用户及服务端而言,性能和延迟都会增加很多。并且如果每一次浏览器跟服务端断开连接以后,又要进行一次整体的建立连接的过程。为了减少客户端和服务端的断开重连过程,这时就需要在Nginx中配置ssl_session_cache 发挥作用。

下面我们来说下这个配置原理,当浏览器跟服务端建立第一次加密证书验证的会话后,服务端会给客户端浏览器缓存一个 SessionKey,如果客户端跟服务端再次断开连接,这时浏览器就可以拿SessionKey 直接跟服务端进行交互。只需要进行一次校验,就可以开始数据传输。我们看到有了SessionKey 这种方式后,就可以避免浏览器跟服务端频繁的进行 HTTPS 会话的建立连接。

通过在 Nginx 中添加 ssl_session_cache 配置,配置中分配 Nginx 在处理 SSL 会话所需要开辟的共享内存的空间,我这里这里设置值为 10 MB,第二个参数就是设置 SSL SessionKey 的超时时间,这里设置的为 10 分钟,也就是每隔 10 分钟需要重新再进行一次建联,这是一个在服务端的超时时间。

打开文件缓存

打开文件缓存设置在 Nginx 端,通常而言我们会把一些静态元素(如:JPG、CSS、GS)在代理端通过这种方式进行设置,这里 Nginx 缓存的是静态元素的元数据。那么把元数据缓存到 Nginx 端有什么好处?元数据的作用就是缓存打开用户所请求的静态元素的文件路径等信息,那么如果在本地频繁地查找之前请求过的静态元素文件而没有缓存元数据时效率比较低,而如果我们把一部分索引数据缓存到Nginx 的 Cache 下,这种频繁访问就可以很大地提高访问效率。

我们来看 open_file_cache 具体的设置策略,max 表示最大能够缓存的文件个数,inactive 表示最少的用户使用次数。我们结合看一下,这个表示在 20 秒内最小需要使用两次。如果没有使用的话,就会把元数据删掉,也这就是一个淘汰元数据的策略。

open_file_cache_valid 是设置主动更新和检查的时间,表示每隔 30 秒检查缓存文件的元信息有没有对应的更新,如果有更新就需要去做对应的更新,它是一个更新的策略。

代理缓存优化

代理缓存比较常见,比如说代理 访问PHP 后台服务并作缓存,也可以代理 JAVA 服务,缓存 JAVA后台服务的返回数据,注意这里不局限于通过 http_proxy来作代理缓存,只要 Nginx 支持的代理模式(UWSGI、SGI)都可以设置代理缓存。你可以来看一下通过http_proxy设置的如下示例:

proxy_cache_path /path/to/cache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m
location / {
proxy_cache my_cache;

}

proxy_cache_path 表示在本地分配哪个路径来存储并缓存后台返回数据;cache levels 表示存放文件的分层方式;my_cache:10m max_size=10g 分别表示是开辟一个名为my_cache共享块(用于统计访问次数)及缓存的单个文件的最大大小等。

这些都是做对应的缓存在本地的文件目录相关属性的一些设置。另外一块的设置表示在proxy_cache 的时候,通过 location 引用到cache 的名称。

代理缓存的特性是什么呢?首先通过 Nginx 作代理,可以支持实现动静态的分离,静态元素直接交给Nginx 来处理,再把后端动态数据适当作缓存。通常做这种代理+缓存的架构,是能有效的提高整体网站的访问并发性能。

对于我们提到的服务端的缓存优化大多交给开发来做 这里就不再做非 Nginx 的缓存配置的讲解了。

缓存使用注意问题

对于缓存的整体使用,之前说的缓存越多越好,越靠前越好,命中率越高越好,但是同时我们也需要综合考虑,并且注意缓存在使用时遇到的一些实际问题。

  1. 文件更新策略问题。文件后端做缓存的配置策略的时候,要考虑到缓存的删除策略、更新策略。怎么保证它的后端数据更新对于前端用户能够及时的感知。

  2. 缓存命中率失败给后端造成的瞬间压力。我们知道,当前端缓存的元素越多,命中率越高,对于后台的压力就越少。当一旦前段的缓存失效,或者某个节点迁移,或者某一部分的前端头信息失效,造成后端缓存瞬间压力,就可能会造成比较灾难性的后果。所以你在网站设计的时候也需要考虑,怎么去避免这种缓存失效?一旦前端缓存失效,你怎么保证后端服务的高可用而不受影响?

  3. 多节点缓存一致性。你在做缓存设置的时候也需要考虑到,假设前端有很多个节点,保存同样的一部分内容的时候,怎么保证这些数据是能够达到一致性,这个时候也涉及缓存架构的设计,前端的缓存节点的更新策略,这些也是你在实际使用缓存时应该注意的问题。


未完待续



文章优先发于公众号运维大师兄


以上是关于安全开发运维必备的Nginx代理Web服务器性能优化与安全加固配置的主要内容,如果未能解决你的问题,请参考以下文章

web服务器—nginx

运维高手二:nginx高性能优化配置实战

Web性能优化——代理(nginx)

阿里P8整理出Nginx笔记:Nginx应用与运维实战核心篇

前端开发者必备的 Nginx 知识

Nginx 应用与运维实战