[TOC]



修订控制页

版本 |修订日期 |修订人 |修订摘要
—|—|—|—
1.0| 2019年9月8日 09点18分 |WeiyiGeek |初稿


1.引言

1.1 目的

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

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

  • 模块性能优化
  • 系统内核优化
  • 编译安装优化
  • 性能参数优化
  • 安全加固配置
1.2 目标范围

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

1.3 读者对象

1) 项目经理
2) 开发人员
3) 测试人员
4) 运维人员
5) 相关领导


2.参考说明

2.1 帮助参考

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

Nginx版本选择:

  • Mainline version 最新版本,推荐测试的业务项目的时候使用
  • Stable version 稳定版本,推荐项目上线实际使用
  • Legacy versions 历史版本,不推荐选择可能存在脆弱性漏洞

项目结构:

#编译后的nginx项目结结构
/etc/nginx/
├── client_body_temp #客户端上面的临时文件存放目录
├── conf #nginx的配置文件存放目录
├── fastcgi_temp #fastcgi的临时文件存放目录
├── html #存放静态资源或者脚本文件的地方
├── logs #nginx日志文件
├── proxy_temp #nginx正向/反向代理缓存文件存放目录
├── sbin #nginx可执行文件
├── scgi_temp #scgi临时文件目录
└── uwsgi_temp #uwsgi临时文件存放目录


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

  • /etc/nginx/nginx.conf
  • /usr/local/nginx/conf/nginx.conf
  • /usr/local/etc/nginx/nginx.conf


2.2 参数说明

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

语法规则: location [=|~|~*|^~] /uri/ { ... }

= 表示精确匹配,这个优先级也是最高的

^~ 表示 uri 以某个常规字符串开头,理解为匹配 url 路径即可。nginx 不对 url 做编码,因此请求为/static/20%/aa,可以被规则^~ /static/ /aa 匹配到(注意是空格)

~ 表示区分大小写的正则匹配

~* 表示不区分大小写的正则匹配(和上面的唯一区别就是大小写) !~和!~*分别为区分大小写不匹配及不区分大小写不匹配的正则

/ 通用匹配,任何请求都会匹配到,默认匹配.


3.3 模块说明

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

#可以通过运行 "./configure --help" 查看编译帮助,决定是否需要安装哪些模块,比如下面的ssi模块能够实现访问shtml页面
./configure -help


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

gzip_min_length 1k #设置允许压缩的页面最小字节数页面字节数从content-length中进行获取,默认值是20
gzip_buffers 4 16k #设置系统获取几个单位的缓存用于存储gzip的压缩结果数据流。4 16k代表以16k为单位,安装原始数据大小以16k为单位的4倍申请内存。
gzip_comp_level 2 #gzip压缩比,其值从1到9数字越大压缩率越高,越消耗CPU负载也越高
gzip_types #匹配mime类型进行压缩,无论是否指定”text/html”类型总是会被压缩的,推荐配置:`gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript。`
gzip_http_version 1.0 #用于识别 http 协议的版本早期的浏览器不支持 Gzip 压缩,用户就会看到乱码,所以为了支持前期版本加上了这个选项;如果你用了 Nginx 的反向代理并期望也启用 Gzip 压缩的话,由于末端通信是 http/1.0,故请设置为 1.0。
gzip_proxied any #Nginx作为反向代理的时候启用,决定开启或者关闭后端服务器返回的结果是否压缩,匹配的前提是后端服务器必须要返回包含”Via”的 header头。
gzip_vary on #和http头有关系会在响应头加个 Vary: Accept-Encoding ,可以让前端的缓存服务器缓存经过gzip压缩的页面,例如用Squid缓存经过Nginx压缩的数据。


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

指令:fastcgi_temp_path  #定义FastCGI缓存文件保存临时路径。
指令:fastcgi_cache_path #定义FastCGI缓存文件保存路径和缓存的其它参数。缓存数据以二进制数据文件形式存储,缓存文件名和key都是通过对访问URL使用MD5计算获得的结果。缓存文件先保存至fastcgi_temp_path指定的临时目录下,然后通过重命名操作移至fastcgi_cache_path指定的缓存目录。建议fastcgi_temp_path和fastcgi_cache_path设为同一分区,同分区移动操作效率更高。示例:
fastcgi_temp_path /tmp/fastcgi_temp;
fastcgi_cache_path /tmp/fastcgi_cache levels=1:2 keys_zone=cache_fastcgi:16m inactive=30m max_size=1g;
# levels指定了目录结构,子目录数以16为基数;
# keys_zone指定了共享内存区名和大小,用于保存缓存key和数据信息;
# inactive指定了缓存数据保存的时间,当这段时间内未被访问将被移出;
# max_size指定了缓存使用的最大磁盘空间,超过容量时将最近最少使用数据删除。
#示例中使用/tmp/fastcgi_temp作为FastCGI缓存的临时目录;/tmp/fastcgi_cache作为FastCGI缓存保存的最终目录;一级子目录为16的一次方16个,二级子目录为16的2次方256个;共享内存区名为cache_fastcgi,占用内存128MB;缓存过期时间为30分钟;缓存数据保存于磁盘的最大空间大小为1GB。

指令:fastcgi_cache_key #定义FastCGI缓存关键字。启用FastCGI缓存必须加上这个配置,不然访问所有PHP的请求都为访问第一个PHP文件URL的结果。
指令:fastcgi_cache_valid #为指定的Http状态码指定缓存时间。
指令:fastcgi_cache_min_uses #指定经过多少次请求相同的URL将被缓存。
指令:fastcgi_cache_use_stale #指定当连接FastCGI服务器发生错误时,哪些情况使用过期数据回应。
指令:fastcgi_cache #缓存使用哪个共享内存区


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

  • keepalive_timeout 闲长连接保持打开状态的时间;
  • keepalive_requests 单个客户端长连接可以请求的数量;
  • keepalive 上游服务器长连接的相关指令,每个工作进程中空闲长连接到上游服务器保持开启的连接数量(没有默认值)。
    要使用连接到上游服务器的长连接,必须要配置文件中下面的指令:
    proxy_http_version 1.1;
    proxy_set_header Connection "";


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

#Nginx SSL性能调优
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
#注意这里的加密方式
ssl_ciphers ECDHE-RSA-AES256-SHA384:AES256-SHA256:RC4:HIGH:!MD5:!aNULL:!eNULL:!NULL:!DH:!EDH:!AESGCM;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;


3.服务优化

3.1 系统内核

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

  • 临时方法可以通过调整/Proc文件系统,需要注意调整/Proc文件系统系统重启后还原至默认值(不推荐)。
  • 永久修改/etc/sysctl.conf配置文件永久保存

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

grep -q "net.ipv4.tcp_max_tw_buckets" /etc/sysctl.conf || cat >> /etc/sysctl.conf << EOF
########################################
net.core.rmem_default = 262144
net.core.rmem_max = 16777216
net.core.wmem_default = 262144
net.core.wmem_max = 16777216

#缓冲区队列设置与连接及其如何排队相关#
#调节系统同时发起的tcp连接数,在高并发的请求中,默认的值可能会导致链接超时或者重传,因此需要结合并发请求数来调节此值。
#net.core.somaxconn = 262144
#在提交到CPU前网卡中数据包缓冲的速率,高带宽下提高这个值可提高性能;检查内核日志文件中有关这个设置的错误,根据网卡文档中的建议修改这个值。
net.core.netdev_max_backlog = 262144
#设定系统中最多有多少个TCP套接字不被关联到任何一个用户文件句柄上
net.ipv4.tcp_max_orphans = 262144
#用于记录那些尚未收到客户端确认信息的连接请求的最大值(根据类才更改)
net.ipv4.tcp_max_syn_backlog = 1024

#设定timewait的数量默认是180000设为10000。
net.ipv4.tcp_max_tw_buckets = 10000

#在高并发情况端口值的起止范围一般端口号设置是1024到65000,用来设定允许系统打开的端口范围;
net.ipv4.ip_local_port_range = 1024 65500

#用于设置启用timewait快速回收
net.ipv4.tcp_tw_recycle = 1

#用于设置开启重用,允许将TIME-WAIT sockets重新用于新的TCP连接。
net.ipv4.tcp_tw_reuse = 1

#用于设置开启SYN Cookies,当出现SYN等待队列溢出时,启用cookies进行处理。
net.ipv4.tcp_syncookies = 1

#决定了内核放弃连接之前发送SYN+ACK包的数量。
net.ipv4.tcp_synack_retries = 1
#表示在内核放弃建立连接之前发送SYN包的数量。
net.ipv4.tcp_syn_retries = 1
#决定了套接字保持在FIN-WAIT-2状态的时间。默认值是60秒。
#正确设置这个值非常重要,有时即使一个负载很小的Web服务器,也会出现大量的死套接字而产生内存溢出的风险。
net.ipv4.tcp_fin_timeout = 30
#选项表示当keepalive启用的时候,TCP发送keepalive消息的频度。默认值是2(单位是小时)。
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_mem = 786432 1048576 1572864
fs.aio-max-nr = 1048576

#文件描述符系统级别的限制#
fs.file-max = 6815744
kernel.sem = 250 32000 100 128
vm.swappiness = 10
EOF
sysctl -p


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

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

#修改文件描述符方式
vim /etc/security/limits.conf
* - nofile 65536 #用户级别文件描述符限制

#然后进行启动文件修改
echo "ulimit -Hsn 65536" >> /etc/profile


3.2 编译优化

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

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

  • 编译Nginx时默认以debug模式进行,而在debug模式下会插入很多跟踪和ASSERT之类的信息,编译完成后一个Nginx要有好几兆字节;因此可以在编译之前,修改相关源码,取消debug模式;
    # 找到源码目录下 auto/cc/gcc  文件 debug
    CFLAGS="$CFLAGS -g" #注释掉或删掉这两行,即可取消debug模式。

    ls -alh /usr/local/nginx/sbin/nginx
    -rwxr-xr-x. 1 root root 915K Aug 17 09:49 /usr/local/nginx/sbin/nginx #可以看到体积大大减少


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

  • Nginx源码文件 auto/cc/gcc 搜索 NGX_GCC_OPT默认GCC编译参数为-O,可以直接修改内容为 NGX_GCC_OPT="-O2" 或者在 ./configure配置时添加--with-cc-opt='-O2'选项
--with-cc-opt='-O3'  #编译级别
--with-cpu-opt=CPU #为特定的 CPU 编译,有效的值包括:pentium, pentiumpro, pentium3, # pentium4, athlon, opteron, amd64, sparc32, sparc64, ppc64

WeiyiGeek.

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

  • -O0:无优化。
  • -O和-O1:使用能减少目标代码尺寸以及执行时间并且不会使编译时间明显增加的优化,在编译大型程序的时候会显著增加编译时内存的使用。
  • -O2:包含-O1的优化并增加了不需要在目标文件大小和执行速度上进行折衷的优化。编译器不执行循环展开以及函数内联。此选项将增加编译时间和目标文件的执行性能。
  • -Os:可以看成 -O2.5,专门优化目标文件大小,执行所有的不增加目标文件大小的-O2优化选项,并且执行专门减小目标文件大小的优化选项。适用于磁盘空间紧张时使用。但有可能有未知的问题发生,况且目前硬盘容量很大,常用程序无必要使用。
  • -O3:打开所有 -O2 的优化选项外增加 -finline-functions、-funswitch-loops、-fgcse-after-reload 优化选项。相对于 -O2 性能并未有较多提高,编译时间也最长,生成的目标文件也更大更占内存,有时性能不增反而降低,甚至产生不可预知的问题(包括错误),所以并不被大多数软件安装推荐,除非有绝对把握方可使用此优化级别。


常用编译参数:

#编译0:常规编译参数
configure arguments:
#安装的目录或者路径#
--prefix=/etc/nginx
--sbin-path=/usr/sbin/nginx
--modules-path=/usr/lib64/nginx/modules
--conf-path=/etc/nginx/nginx.conf
--error-log-path=/var/log/nginx/error.log
--http-log-path=/var/log/nginx/access.log
--pid-path=/var/run/nginx.pid
--lock-path=/var/run/nginx.lock
#执行对应模块nginx所保留的临时文件#
--http-client-body-temp-path=/var/cache/nginx/client_temp
--http-proxy-temp-path=/var/cache/nginx/proxy_temp
--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp
--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp
--http-scgi-temp-path=/var/cache/nginx/scgi_temp
#启动的用户和组用户#
--user=nginx
--group=nginx
#模块参数#
--with-compat
--with-file-aio
--with-threads
--with-http_addition_module
--with-http_auth_request_module
--with-http_dav_module
--with-http_flv_module
--with-http_gunzip_module
--with-http_gzip_static_module
--with-http_mp4_module
--with-http_random_index_module
--with-http_realip_module
--with-http_secure_link_module
--with-http_slice_module
--with-http_ssl_module
--with-http_stub_status_module
--with-http_sub_module
--with-http_v2_module
--with-mail
--with-mail_ssl_module
--with-stream
--with-stream_realip_module
--with-stream_ssl_module
--with-stream_ssl_preread_module
#设置额外的参数将被添加到CFLAGS#
--with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC'
#设置附件参数,链接系统库#
-with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie'


#编译1:除多余模块
./configure \
"--prefix=/App/nginx" \
"--user=nginx" \
"--group=nginx" \
"--with-http_stub_status_module" \
"--without-http_auth_basic_module" \
"--without-http_autoindex_module" \
"--without-http_browser_module" \
"--without-http_empty_gif_module" \
"--without-http_geo_module" \
"--without-http_limit_conn_module" \
"--without-http_limit_req_module" \
"--without-http_map_module" \
"--without-http_memcached_module" \
"--without-http_proxy_module" \
"--without-http_referer_module" \
"--without-http_scgi_module" \
"--without-http_split_clients_module" \
"--without-http_ssi_module" \
"--without-http_upstream_ip_hash_module" \
"--without-http_upstream_keepalive_module" \
"--without-http_upstream_least_conn_module" \
"--without-http_userid_module" \
"--without-http_uwsgi_module" \
"--without-mail_imap_module" \
"--without-mail_pop3_module" \
"--without-mail_smtp_module" \
"--without-poll_module" \
"--without-select_module" \
"--with-cc-opt='-O2'"


3.3 性能优化

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

  • 1)缓存
    一个启用NGINX缓存的情景,一组web或者应用服务器负载均衡,可以显著缩短对客户端的响应时间,同时大幅度降低后端服务器的负载。缓存本身就可以作个专题来讲,这里我们就不试图讲它了。
  • 2)压缩
    所以使用更小的网络带宽。然而尽管压缩数据会消耗CPU资源,但当需要减少网络带宽使用时这样做非常有效。需要注意的是,不能对已压缩的文件再压缩例如JPEG 文件。
  • 3)限制
    防止用户消耗太多的资源,避免影响系统性能和用户体验及安全以下是相关的指令:
    limit_conn and limit_conn_zone  #NGINX接受客户连接的数量限制,例如单个IP地址的连接。设置这些指令可以防止单个用户打开太多的连接,消耗超出自己的资源。
    limit_rate #传输到客户端响应速度的限制(每个打开多个连接的客户消耗更多的带宽)。设置这个限制防止系统过载,确保所有客户端更均匀的服务质量。
    limit_req and limit_req_zon #NGINX处理请求的速度限制,与limit_rate有相同的功能。可以提高安全性,尤其是对登录页面,通过对用户限制请求速率设置一个合理的值,避免太慢的程序覆盖你的应用请求(比如DDoS攻击)。
    max_conns #上游配置块中服务器指令参数。在上游服务器组中单个服务器可接受最大并发数量。使用这个限制防止上游服务器过载。设置值为0(默认值)表示没有限制。
    queue (NGINX Plus) #创建一个队列,用来存放在上游服务器中超出他们最大max_cons限制数量的请求。这个指令可以设置队列请求的最大值,还可以选择设置在错误返回之前最大等待时间(默认值是60秒)。如果忽略这个指令,请求不会放入队列。


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

位置 指令 说明 优化
main worker_processes 工作进程数的选择包括(但不限于)CPU核心的数量、存储数据的硬盘数量及负载模式 设置 auto 或者 `cat /proc/cpuinfo grep processor wc -l` 服务器逻辑核心总数
main worker_cpu_affinity Nginx默认未开启CPU绑定,绑定工作进程到对应CPU核心 多核CPU建议设置CPU绑定,绑定样例:
worker_processes 4;
worker_cpu_affinity 0001 0010 0100 1000;
main worker_rlimit_nofile 打开文件数限制(默认值1024),受限于系统的用户进程打开文件数限制,未设置则使用系统默认值 修改用户打开文件数限制:
echo "* - nofile 65536" >> /etc/security/limits.conf
修改所有Shell和通过Shell启动的进程打开文件数限制:
echo "ulimit -n 65536" >> /etc/profile
临时生效(重启后生效): ulimit -n 65536
main worker_connections Nginx一个工作进程的最大同时连接数,不仅限于客户端连接,包括了和后端被代理服务器等其他的连接 建议设置成与 worker_rlimit_nofile 值相等
mian sendfile 在http或server或location环境中包含sendfile指令。
NGINX可以不需要切换到用户态,就把缓存或磁盘上的内容写入套接字而且写的速度非常快,消耗更少的CPU周期。
注意尽管使用sendfile()数据拷贝可以绕过用户态但不适用于常规的NGINX处理改变内容的链和过滤器比如gzip
建议设置成 on
main-events accept_mutex 惊群问题:
如果指令值为 on 启用,那么将轮流唤醒一个工作进程接收处理新的连接,其余工作进程继续保持睡眠
如果指令值为 off 关闭,那么将唤醒所有工作进程,由系统通过use指令指定的网络IO模型调度决定由哪个工作进程处理,未接收到连接请求的工作进程继续保持睡眠
on开启状态为了稳定参数值;
off关闭状态提高性能和吞吐量但是会带来上下文切换增多或者负载升高等等其它资源更多消耗的后果(推荐)
main-events use 定义了Nginx设置用于复用客户端线程的轮询方法(也可称多路复用网络IO模型),自然是选择效率更高的优先(默认即可) use epoll
main open_file_cache 开启关闭打开文件缓存默认值 off 关闭,强烈建议开启可以避免重新打开同一文件带来的系统开销节省响应时间 max=数字设置缓存元素的最大数量
inactive=时间设置超时 当缓存溢出时使用LRU(最近最少使用)算法删除缓存中的元素;在这段时间内缓存元素如果没有被访问将从缓存中删除;
open_file_cache max=65536 inactive=60s
main open_file_cache_valid 设置检查open_file_cache缓存的元素的时间间隔 80s
main open_file_cache_min_uses 设置在由open_file_cache指令的inactive参数配置的超时时间内文件应该被访问的最小次数。
如果访问次数大于等于此值,文件描述符会保留在缓存中,否则从缓存中删除。
1
main error_log 错误的访问请求日志记录,当并发很大时Nginx的访问日志和错误日志的保存肯定会造成对磁盘的大量读写也将影响Nginx的性能 注释即可 或者 错误日志设置为 error 或者 crit
main-http access_log 成功的访问请求日志记录, 如必须保存日志,可以按每日或者每时或者其它时间段对日志做切割,这也可以减小IO,虽然可能效果不是特别大,不过因为日志文件尺寸变小了很多,也方便查阅或归档分析日志 建议开启日志记录级别 main
main-http gzip 默认开启了gzip压缩功能:增加CPU的处理时间和负载(默认即可)
关闭gzip压缩功能:虽然减少了CPU计算节省了服务器的响应时间,但网站页面总体响应时间反而加长了静态文件数据传输时间增加;
设置 gzip on 即可;(该模块中有附带参数)
main-http keepalive_timeout 空闲长连接保持打开状态的时间;复用之前已建立的TCP连接接收请求、发送回应,减少重新建立TCP连接的资源时间开销 正数为开启持久连接(常规设置120)而0关闭。
当网站页面内容以静态为主时,开启持久连接;
动态网页且不能被转化为静态页面,则关闭持久连接;
main-http keepalive_requests 单个客户端长连接可以请求的数量但是当使用压力测试工具从一个客户端发送多个请求测试时,这个值设更高些特别有用 默认值是100
main-http-server-location expires 浏览器缓存设置HTTP应答中的“Expires”和“Cache-Control”头标。”Expires”一般结合”Last-Modified”使用比较缓存时间,避免了从服务器再次传送文件内容减小了服务器压力,节省了带宽同时也提高了用户访问速度 -1 表示永远过期不缓存,推荐静态文件如js/css等等访问设置 expires 30da;


4.安全配置

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

Nginx安全配置项:
0.隐藏nginx版本和服务名称修改后重新编译一下环境

#方式1:
#vi nginx-1.9.11/src/http/ngx_http_header_filter_module.c
static char ngx_http_server_string[] = "Server: LTWS" ; #修改处
#修改nginx_http_header_filter_module
#vi nginx-1.9.11/src/http/ngx_http_special_response.c
static u_char ngx_http_error_full_tail[] =
"<center> NGINX_VER </center>"
"<hr><center> http://www.weiyigeek.com</center>"
"</body>"
"</html>"
;

static u_char ngx_http_error_tail[] =
"<hr><center>LTWS</center>"
"</body>"
"</html>"
;

#设置响应头版本版本
#vim src/core/nginx.h
#define NGINX_VERSION "secWaf" #可以改成你要的版本号
#define NGINX_VER "1.1" NGINX_VERSION #改成你的服务名称

WeiyiGeek.
设置成功后验证:
WeiyiGeek.


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

加固方法:

groupadd nginxweb;
useradd -M -g nginxweb -s /sbin/nologin nginxweb

#nginx.conf 中配置 或者编译 的时候指定
#nginx 安装编译参数--user=nginx --group=nginx
user nginxweb


2.配置SSL协议
应配置使用Secure Sockets Layer Protocol (SSL协议);为了数据传输的安全,SSL依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密。

#可用站点默认文件包含 
ssl on
ssl_prefer_server_ciphers on;


3.限制SSL协议和密码
不应使用不安全SSLv2协议即以下和脆弱性的ciphers,较新的TLS协议也应该优于旧的,并使用安全的加密密钥

#ssl_ciphers 字段应包含 
ssl_ciphers ECDHE-RSA-AES256-SHA384:AES256-SHA256:RC4:HIGH:!MD5:!aNULL:!eNULL:!NULL:!DH:!EDH:!AESGCM;


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

if ( $http_referer ~* (babes|forsale|girl|jewelry|love|nudit|organic|poker|porn|sex|teen) ){
# return 404;
return 403;
}


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

#编译时候需要采用:--with-http_geoip_module
if ( $geoip_country_code !~ ^(CN|US)$ ) {
return 403;
}

#封杀各种user-agent
if ($http_user_agent ~* "java|python|perl|ruby|curl|bash|echo|uname|base64|decode|md5sum|select|concat|httprequest|httpclient|nmap|scan|nessus|wvs" ) {
return 403;
}

if ($http_user_agent ~* "" ) {
return 403;
}

#封杀特定的文件扩展名比如.bak以及目录;
location ~* \.(bak|swp|save|sh|sql|mdb|svn|git|old)$ {
rewrite ^/(.*)$ $host permanent;
}
location /(admin|phpadmin|status) { deny all; }

WeiyiGeek.


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


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


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


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


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

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


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

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


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

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


13.Nginx可用的方法应限制为GET, HEAD, POST
GET和POST是Internet上最常用的方法。Web服务器方法在RFC 2616中定义禁用不需要实现的可用方法。

加固方法:

#nginx.conf文件中应存在
if ($request_method !~ ^(GET|HEAD|POST)$ )


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

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


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

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


16.主机防webshell跨目录浏览以及列目录
加固方法:

a.在nginx.conf里把每个虚拟主机站点请求端口给区别开
b.为每个站点建一个conf,并进行配置
c.修改php-fpm启动脚本
d.启动服务

#在main-http-server段中设置开启或者关闭(对于需要列目录的则开启,否则默认是关闭的)
autoindex off


17.文件名解析漏洞php_info,加入fcgi.conf即可

if ($request_filename ~* (.*)\.php) {
set $php_url $1;
}

if (!-e $php_url.php) {
return 403;
}


18.访问权限控制nginx
加固方法:

#nginx.conf
location ~ ^/script/ {
auth_basic "welcome to weiyigeek.github.io";
auth_basic_user_file /var/www/test/script/.htpasswd;
}

#建立htpasswd密码进行认证
mkdir /var/www/test/script
perl -e "print crypt('baidu.eud',"n");"
nnUygd3RSf3u6

echo 'nginx:nnUygd3RSf3u6' > /var/www/test/script/.htpasswd
/usr/local/nginx/sbin/nginx -s reload

WeiyiGeek.


19.一类状态返回200隐藏URL
解决办法:·

server{
listen 80;
server_name aqzt.com;
index index.html index.htm index.php;
root /data/web;
error_page 404 =200 /404.jpg;
}


20.安全模块的选择

#模块选择
http_sub_module
http_stub_status_module
xss-nginx-module
with-http_ssl_module


5.配置说明

常用nginx配置文件解释:

#[Main] Nginx启动的用户(建议非root用户)
user nginx;

#[Main] NGINX工作进程数设置值和CPU核心数一致(优化选项)
#采用 grep ^processor /proc/cpuinfo | wc -l 进行查看或者auto
worker_processes auto;

#[Main] 工作模式与连接数上限即每个工作进程可以处理并发的最大连接数(优化选项)
events {
#[Main-events] nginx作为反向代理服务器单个进程最大连接数(最大连接数=连接数*进程数)
#建议与worker_rlimit_nofile一致
worker_connections 65535;
#[Main-events] use [ kqueue | rtsig | epoll | /dev/poll | select | poll ];
#epoll模型是Linux 2.6以上版本内核中的高性能网络I/O模型,如果跑在FreeBSD上面,就用kqueue模型。
use epoll;
#[Main-events] 提高性能和吞吐量
accept_mutex off;
}

#[Main] 高并发参数(通过设置cpu粘性来降低由于多CPU核切换造成的寄存器等现场重建带来的性能损耗)(优化选项)
worker_cpu_affinity 0001 0010 0100 1000; #四核的时候
#假如是8 cpu 分配如下: worker_cpu_affinity 00000001 00000010 00000100 00001000 0001000000100000 01000000 10000000

#[Main] 默认是没有设置,可以限制为操作系统最大的限制65535。(优化选项)
worker_rlimit_nofile 65535

#[Main]日志位置和日志级别[ debug | info | notice | warn | error | crit ]
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
error_log logs/error.log error;

#服务进程启动文件
pid /var/run/nginx.pid;

#当前主配置文件包含其他的nginx模块配置文件
include /etc/nginx/conf.d/*.conf;

#[Main部分] http服务器提供http服务相关的一些配置参数。例如:是否使用keepalive啊,是否使用gzip进行压缩等。
http {
#文件扩展名与文件类型映射表
include mime.types;
#默认文件类型
default_type text/html;
#响应的编码格式
charset UTF-8;
#服务器名字的hash表大小
server_names_hash_bucket_size 128;
#缓冲区代理缓冲用户端请求的最大字节数,
client_body_buffer_size 128k
#上传文件大小限制
client_header_buffer_size 4k;
#允许客户端请求的最大单文件字节数。如果有上传较大文件,请设置它的限制值
client_max_body_size 10m

#文件访问缓存设置与系统文件描述符设置一致
open_file_cache max=65536 inactive=60s;
open_file_cache_valid 80s;
open_file_cache_min_uses 1;

large_client_header_buffers 4 64k; #设定请求缓

#nginx日志记录格式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

#使用缓冲而不是每条日志记录都单独执行写操作,NGINX会缓冲一连串的日志记录使用单个操作把它们一起写到文件中。
access_log logs/access.log main buffer=1024 flush=60s;

#关闭server信息头响应
server_tokens off;


#[MAIN-http]开启高效文件传输模式,指定nginx是否调用sendfile函数来输出文件,减少用户空间到内核空间的上下文切换(与accept_mutex关联配置)
#对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。
#系统调用可以实现从一个文件描述符到另一个文件描述符的数据拷贝,通常实现零拷贝,这能加速TCP数据传输
#当配置环境下有sendfile指令和激活内容更改过滤器的指令时NGINX会自动禁用sendfile。#(优化选项)
sendfile on;
#防止网络阻塞,不过要包涵在keepalived参数才有效
tcp_nopush on;
tcp_nodelay on;

#空闲长连接保持打开状态的时间(优化选项)
#长连接请求大量小文件的时候,可以减少重建连接的开销,但假如有大文件上传120s内没上传完成会导致失败。如果设置时间过长,用户又多,长时间保持连接会占用大量资源。
keepalive_timeout 120;

#用于指定响应客户端的超时时间。这个超时仅限于两个连接活动之间的时间,如果超过这个时间客户端没有任何活动,Nginx将会关闭连接
#send_timeout 180s

###模块http_gzip#####
#开启gzip压缩输出,减少网络传输。
gzip on;
#最小压缩文件大小(注意不能小于1k)
gzip_min_length 1k;
#压缩缓冲区
gzip_buffers 4 64k;
#压缩版本(默认1.1,前端如果是squid2.5请使用1.0)
gzip_http_version 1.1;
#压缩等级
gzip_comp_level 2;
##压缩类型,默认就已经包含text/html,
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

###模块fastcgi#####
#FastCGI相关参数是为了改善网站的性能:减少资源占用,提高访问速度。
# fastcgi_temp_path /tmp/fastcgi_temp;
# fastcgi_cache_path /tmp/fastcgi_cache levels=1:2 keys_zone=cache_fastcgi:128m inactive=30m max_size=1g;
# fastcgi_cache_key $host$request_uri;
#指定的Http状态码指定缓存时间
# fastcgi_cache_valid 200 302 1h;
# fastcgi_cache_valid 301 1d;
# fastcgi_cache_valid any 1m;
# fastcgi_cache_min_uses 1;
# fastcgi_cache_use_stale error timeout http_500 http_503 invalid_header;
#指定链接到后端FastCGI的超时时间。
# fastcgi_connect_timeout 300;
#向FastCGI传送请求的超时时间,这个值是指已经完成两次握手后向FastCGI传送请求的超时时间。
# fastcgi_send_timeout 300;
#指定接收FastCGI应答的超时时间,这个值是指已经完成两次握手后接收FastCGI应答的超时时间。
# fastcgi_read_timeout 300;
#指定读取FastCGI应答第一部分需要用多大的缓冲区,这个值表示将使用1个64KB的缓冲区读取应答的第一部分(应答头),可以设置为gastcgi_buffers选项指定的缓冲区大小。
# fastcgi_buffer_size 64k;
#一个php脚本所产生的页面大小为256KB,那么会分配4个64KB的缓冲区来缓存
# fastcgi_buffers 4 64k;
#建议设置为fastcgi_buffer的两倍,繁忙时候的buffer
# fastcgi_busy_buffers_size 128k;
# fastcgi_temp_file_write_size 128k;


#[Main-http]配置虚拟主机设置
#http服务上支持若干虚拟主机。每个虚拟主机一个对应的server配置项,配置项里面包含该虚拟主机相关的配置
server {
#[Main-http-server] ngnix监听端口
listen 80;

#服务器名:虚拟主机的域名可以写多个域名,可以通过正则匹配。
server_name localhost;

#实现访问http时自动跳转到https
return 301 https://$host$request_uri;
#access_log logs/host.access.log main;

#请求正则匹配的来判断访问路径,默认访问localhost:80 访问的是下面这个路径的网页
location / {
#站点根目录你网站文件存放的地方
root html;
#定义路径下默认访问的文件名,一般跟着root放
index index.html index.htm;

#开启限制IP连接数的时候需要使用
#limit_zone crawler $binary_remote_addr 10m;

#访问控制模块默认就会安装,而且写法也非常简单,可以分别有多个allow,deny,允许或禁止某个ip或ip段访问,
#依次满足任何一个规则就停止往下匹配 (安全选项)
allow 192.168.10.100;
allow 172.29.73.0/24;
deny all;

#认证访问 通过httpd-devel 工具的 htpasswd 来为访问的路径设置登录密码 (安全选项)
#比如:htpasswd -c nginx.htpasswd admin 生成了默认使用CRYPT加密的密码文件#
auth_basic "Nginx Status"
auth_basic_user_file /usr/local/nginx/nginx.passwd

#列出目录 autoindex Nginx默认是不允许列出整个目录的合适下载服务器。(非常不推荐)
#如需此功能,打开nginx.conf文件,在location,server 或 http段中加入autoindex on;
#autoindex on
#显示出文件的确切大小单位是bytes。改为off后显示出文件的大概大小,单位是kB或者MB或者GB
#autoindex_exact_size off
#默认为off,显示的文件时间为GMT时间。改为on后,显示的文件时间为文件的服务器时间
#autoindex_localtime on;
}

#error_page 404 /404.html;
#将服务器错误页面直接指向静态页面/50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}

#代理PHP脚本到Apache上监听127.0.0.1:80 末尾以php或者php5结尾的
#location ~ \.(php|php5)?$ {
# proxy_pass http://127.0.0.1;
#}

#将PHP脚本传递到正在监听127.0.0.1:9000的FastCGI服务器
#location ~ .+\.(php|php5)$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_pass unix:/tmp/php.sock; #为了安全推荐方式
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
# fastcgi_cache cache_fastcgi;
#}


# 如果Apache的文档根目录与nginx的根目录一致,则拒绝访问.htaccess文件
#location ~ /\.ht {
# deny all;
#}

#静态资源正则请求路径匹配
location ~ .+\.(gif|jpg|jpeg|png|bmp|swf|txt|csv|doc|docx|xls|xlsx|ppt|pptx|flv)$ {
root e:wwwroot;
expires 30d; #缓存有效期30天
access_log off; #访问记录
}
#JS和CSS缓存时间设置
location ~ .+\.(js|css|html|xml)$ { expires 30d;}

#访问控制也可以加入认证
location /nginx-status{
#nginx中的stub_status模块主要用于查看Nginx的一些状态信息. 本模块默认没有安装需要编译安装。
stub_status on;
allow 192.168.1.0/24;
allow 127.0.0.1;
deny all;
}
}

#### Nginx反向代理 ######
#[Main-http] upstream模块设置反向代理和负载均衡的连接的内部web应用服务IP端口
upstream monitor_server {
#seesion记录访问的主机,比如第一次访问该服务器后就记录,之后再访问都是该服务器了-进行了绑定
ip_hash;
#内网的应用服务,weigth参数表示权值越高被分配到的几率越大。
#max_fails当有max_fails个请求失败,就表示后端的服务器不可用,默认为1将其设置为0可以关闭检查
#fail_timeout 在以后的fail_timeout时间内nginx不会再把请求发往已检查出标记为不可用的服务器
server 192.168.0.131:80 weight=9 max_fails=5 fail_timeout=600s;
server 192.168.0.132:80 weight=1 max_fails=5 fail_timeout=600s;
}


#server指令配置项
server {
listen 81;
#请求响应的域名
server_name nagios.xxx123.tk;

location / {
##### 模块http_proxy:##### 反向代理主要配置
#即反向代理,对应upstream负载均衡器
proxy_pass http://monitor_server;

#代理服务器相关信息头设置
proxy_redirect off;
#如果是有涉及redirect的服务,一定要加上端口8081,否 则默认tomcat在redirect时候默认找80端口
proxy_set_header Host $host;
#转发请求的原IP地址,程序中通过request.getHeader("Proxy-Client-IP")获得ip
proxy_set_header X-Real-IP $remote_addr;
#端的Web服务器可以通过X-Forwarded-For获取用户真实IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

##nginx跟后端服务器连接超时时间(代理连接超时)
#模块http_proxy代理超时设置
proxy_connect_timeout 60s;

##nginx跟后端服务器连接超时时间(代理连接超时)
proxy_read_timeout 60s;

#后端服务器数据回传时间(代理发送超时) 间
proxy_send_timeout 30s;

#设置代理服务器(nginx)从后端realserver读取并保存用户头信息的缓冲区大小,默认与proxy_buffers大小相同,其实可以将这个指令值设的小一点
proxy_buffer_size 4k
#proxy_buffers缓冲区,nginx针对单个连接缓存来自后端realserver的响应,网页平均在32k以下的
proxy_buffers 4 32k

#高负荷下缓冲大小(proxy_buffers*2)
proxy_busy_buffers_size 64k

#当proxy_buffers放不下后端服务器的响应内容时,会将一部分保存到硬盘的临时文件中,这个值用来设置最大临时文件大小,默认1024M
#它与proxy_cache没有关系。大于这个值,将从upstream服务器传回。设置为0禁用。
proxy_max_temp_file_size 0

#当缓存被代理的服务器响应到临时文件时,限制每次写临时文件的大小。proxy_temp_path(可以在编译的时候)指定写到哪那个目录。
proxy_temp_file_write_size 64k

#把cookie的作用域替换成我们的域名。
#proxy_cookie_domain google.com.hk www.example.com;
#proxy_set_header Host "www.google.com.hk"; #设置反向代理得header请求头
#proxy_redirect http://www.google.com.hk/ ; #重定向
#sub_filter www.google.com.hk www.example.com; #把谷歌的域名替换成自己的,注意需要安装nginx的sub_filter模块
#反向代理的配置. END
}

#本地动静分离反向代理配置
#所有jsp的页面均交由tomcat或resin处理
location ~ .(jsp|jspx|do)?$ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:8080;
}

#所有静态文件由nginx直接读取不经过tomcat或resin
location ~ .*.(htm|html|gif|jpg|jpeg|png|bmp|swf|ioc|rar|zip|txt|flv|mid|doc|ppt|pdf|xls|mp3|wma)$
{ expires 15d; }

location ~ .*.(js|css)?$
{ expires 1h; }

}


# 另一个虚拟主机,混合使用IP、名称和基于端口的配置
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;

# location / {
# root html;
# index index.html index.htm;
# }
#}


# HTTPS server /SSL 设置
#
#server {
# listen 443 ssl;
# server_name localhost;

# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;

# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;

# ssl_ciphers ALL:!EXP:!NULL:!ADH:!LOW:!SSLv2:!MD5:!RC4;
# ssl_prefer_server_ciphers on;

# location / {
# root html;
# index index.html index.htm;
# }
#}
}


补充知识

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


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

  • 1.增加FastCGI进程数:把PHP FastCGI子进程数调到100或以上,在4G内存的服务器上200就可以建议通过压力测试获取最佳值。
  • 2.增加 PHP-FPM打开文件描述符的限制

    # vi /path/to/php-fpm.conf
    找到“1024”,把1024更改为 4096 或者更高,之后重启 PHP-FPM
    # /etc/security/limits.conf
    * hard nofile 65536
    * soft nofile 65536
  • 3.适当增加max_requests: 标签max_requests指明了每个children最多处理多少个请求后便会被关闭默认的设置是500。