优化有原则,过度优化会压榨服务器性能影响到其他应用程序,同时不建议开启压缩传输(如果客户端浏览器不支持解压就尴尬了)。本文涉及到的优化选项有:

1. 设置最佳数量的进程数;

2. 设置CPU亲和力,充分利用cpu的寄存器和高速缓存

3.更改默认的nobody用户名,最好是编译安装时就设置好

4. 调整单进程允许的最大连接数

5. 使用 epoll高并发时间处理模型模型;

6. 关于连接的其他优化

7. 节省资源,不记录不必要的访问日志

8. 错误页面的优雅显示

9. 访问日志的权限设置

10. 限制上传到目录的资源被访问

11. 隐藏版本号,使其不能针对版本漏洞进行渗透攻击

12. 防盗链 (很重要!)

13. fastcgi优化

14. 日志轮询与切割 (很重要!)

15. 内核参数优化

16. 规范使用认证

17. 限制恶意的高频度高并发访问(其实使用iptables更好)

18. 禁止恶意域名解析,禁止通过IP访问本站(慎用!)

19. 优化server_name,location,rewrite3个标签段的设置(话题繁复)

20. 其他有用的设置

下面就这20条总则一一详细阐述。

 

1. 设置最佳数量的进程数;

查看本机cpu有几核:grep processor  /proc/cpuinfo| wc -l

修改此处 worker_processes n;   //n为上条命令查出的结果

nginx 进程数,建议按照cpu 数目来指定,一般为它的倍数 (如,2个四核的cpu计为8)。

 

2. 设置CPU亲和力,合理利用CPU的寄存器与高速缓存

worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;

为每个进程分配cpu,上例中将8 个进程分配到8 个cpu,当然可以写多个,或者将一

个进程分配到多个cpu。

 

3.更改默认的nobody用户名,最好是编译安装时就设置好

./configure --user=用户名 --group=组名

 

4. 调整单进程允许的最大连接数

events {
worker_connections 10240;  //上限是65535
worker_rlimit_nofile 65535;  //默认是512,简直暴殄天物!
}

这个指令是指当一个nginx 进程打开的最多文件描述符数目,理论值应该是最多打开文件数(ulimit -n)与nginx 进程数相除,但是nginx 分配请求并不是那么均匀,所以最好与ulimit -n 的值保持一致。

现在在linux 2.6内核下开启文件打开数为65535,worker_rlimit_nofile就相应应该填写65535。这是因为nginx调度时分配请求到进程并不是那么的均衡,所以假如填写10240,总并发量达到3-4万时就有进程可能超过10240了,这时会返回502错误。

查看linux系统文件描述符的方法:

sysctl -a | grep fs.file

fs.file-max = 98078

fs.file-nr = 928 0 98078

 

5. use epoll;

events {
  use epoll;
  worker_connections 65535;
  multi_accept on;
}

 

6. 关于连接的其他优化

keepalive_timeout 60;

keepalive 超时时间。

client_header_buffer_size 4k;

客户端请求头部的缓冲区大小,这个可以根据你的系统分页大小来设置,一般一个请求头的大小不会超过1k,不过由于一般系统分页都要大于1k,所以这里设置为分页大小。

分页大小可以用命令getconf PAGESIZE 取得。

getconf PAGESIZE

4096

但也有client_header_buffer_size超过4k的情况,但是client_header_buffer_size该值必须设置为“系统分页大小”的整倍数。

 open_file_cache max=65535 inactive=60s;

这个将为打开文件指定缓存,默认是没有启用的,max 指定缓存数量,建议和打开文件数一致,inactive 是指经过多长时间文件没被请求后删除缓存。

open_file_cache_valid 80s;

这个是指多长时间检查一次缓存的有效信息。

open_file_cache_min_uses 1;

open_file_cache 指令中的inactive 参数时间内文件的最少使用次数,如果超过这个数字,文件描述符一直是在缓存中打开的,如上例,如果有一个文件在inactive 时间内一次没被使用,它将被移除。

 

7. 节省资源,不记录不必要的访问日志

location ~ .*\.(js|jpg|JPG|jpeg|JPEG|css|bmp|gif|GIF)$ {
             access_log off; #一些图片的访问就不必记录了
 }

8. 错误页面的优雅显示

http模块中加入

fastcgi_intercept_errors on; 
location / {
。。。。。。
index index.html index.htm;
error_page 400 401 402 403 404 405 408 410 412 413 414 415 500 501 502 503 506 = http://www.xxxx.com/error.html;
}

9. 访问日志的权限设置

location /logs/ {
             deny all; #禁止访问日志             return 404;

 

10. 限制上传到目录的资源被访问

location ~ ^/images/.*\.(php|php5|sh|pl|py)$ {
             deny all; #禁止解析指定目录下的指定程序         
}

11.隐藏版本号,使其不能针对版本漏洞进行渗透攻击

http {
 include mime.types; default_type application/octet-stream; server_tokens off; #关闭版本号

12 防盗链

Nginx的防盗原理是加入location项,用正则表达式过滤图片类型文件,对于信任的网址可以正常使用,对于不信任的网址则返回相应的错误图片。在源主机benet.com的配置文件加入以下代码:

[root@localhost ~]# vim /usr/local/nginx/conf/nginx.conf 
location ~*\.(jpg|gif|swf)$ {
 valid_referers none blocked *.benet.com benet.com; 
if ( $invalid_referer ) {
 rewrite ^/ http://www.benet.com/error.png; 
 } 
}
  • ~*.(jpg|gif|swf)$: 匹配不区分大小写,以.jpg 或.gif或 .swf结尾的文件。
  • valid_referers:设置信任的网站,可以正常使用图片。
  • none:浏览器中refer为空的情况,就是直接在浏览器访问图片。
  • blocked:浏览器中refer不为空的情况,但是值被代理或防火墙删除了,这些值不以http://或 https://开头。
  • 后面的网址或域名:refer包含相关字符串的网址。
  • if语句:如果链接的来源域名不在valid_referers所列出的列表中, $invalid_referer 为1,则执行后面的操作,即进行重写或返回403页面。

13 fastcgi优化

fastcgi_cache TEST

开启FastCGI 缓存并且为其制定一个名称。个人感觉开启缓存非常有用,可以有效降低CPU 负载,并且防止502 错误。

 

14 日志轮询与切割

随着Nginx的运行时间的增加,产生的日志也会增加。太大的日志文件非常不便于分析和排查,因此需要定期的进行日志文件的切割。Nginx没有类似Apache的cronlog日志分割处理功能,但可以通过Nginx的信号控制功能脚本来实现日志的自动切割,并将脚本加入到Linux的计划任务中,让脚本在每天的固定时间执行。

(1)首先编写脚本/opt/fenge.sh,把Nginx的日志文件/usr/local/nginx/logs/access.log移动到目录/var/log/nginx下面,以当前时间作为日志文件的名称,然后用kill-USR1创建新的日志文件/usr/local/nginx/logs/access.log,最后删除前30天的日志文件。

[root@localhost ~]# vim /opt/fenge.sh 
#!/bin/bash
#Filename:fenge.sh
d=$(date -d "-1 day" "+%Y%m%d") #显示一天前的时间
logs_path="/var/log/nginx"
pid_path="/usr/local/nginx/logs/nginx.pid"
[ -d $logs_path ] || mkdir -p $logs_path #创建日志文件目录
mv /usr/local/nginx/logs/access.log #移动并重命名日志文件 
${logs_path}/test.com-access.log-$d
kill -USR1 $(cat $pid_path) #重建新的日志文件
find $logs_path -mtime +30 | xargs rm -rf #删除30天之前的日志文件
件 
${logs_path}/test.com-access.log-$d
kill -USR1 $(cat $pid_path) #重建新的日志文件
find $logs_path -mtime +30 | xargs rm -rf #删除30天之前的日志文件
(2)执行/opt/fenge.sh,测试日志文件是否被切割。
[root@localhost ~]# chmod +x /opt/fenge.sh 
[root@localhost ~]# ./fenge.sh #执行分割脚本 
[root@localhost ~]# ls /var/log/nginx/ test.com-access.log-20180628
(3)设置crontab任务,定期执行脚本自动进行日志分割。
[root@localhost ~]# crontab -e 0 1 * * * /opt/fenge.sh #每天的凌晨1点执行/opt/fenge.sh脚本
15.内核参数优化,调整内核参数很危险调整之前必须多做了解
net.ipv4.tcp_max_tw_buckets = 6000
timewait 的数量,默认是180000。
net.ipv4.ip_local_port_range = 1024 65000
允许系统打开的端口范围。
net.ipv4.tcp_tw_recycle = 1
启用timewait 快速回收。
net.ipv4.tcp_tw_reuse = 1
开启重用。允许将TIME-WAIT sockets 重新用于新的TCP 连接。
net.ipv4.tcp_syncookies = 1
开启SYN Cookies,当出现SYN 等待队列溢出时,启用cookies 来处理。
net.core.somaxconn = 262144
web 应用中listen 函数的backlog 默认会给我们内核参数的net.core.somaxconn 限制到128,而nginx 定义的NGX_LISTEN_BACKLOG 默认为511,所以有必要调整这个值。
net.core.netdev_max_backlog = 262144
每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目。
net.ipv4.tcp_max_orphans = 262144
系统中最多有多少个TCP 套接字不被关联到任何一个用户文件句柄上。如果超过这个数字,孤儿连接将即刻被复位并打印出警告信息。这个限制仅仅是为了防止简单的DoS 攻击,不能过分依靠它或者人为地减小这个值,更应该增加这个值(如果增加了内存之后)。
net.ipv4.tcp_max_syn_backlog = 262144
记录的那些尚未收到客户端确认信息的连接请求的最大值。对于有128M 内存的系统而言,缺省值是1024,小内存的系统则是128。
net.ipv4.tcp_timestamps = 0
时间戳可以避免序列号的卷绕。一个1Gbps 的链路肯定会遇到以前用过的序列号。时间戳能够让内核接受这种“异常”的数据包。这里需要将其关掉。
net.ipv4.tcp_synack_retries = 1
为了打开对端的连接,内核需要发送一个SYN 并附带一个回应前面一个SYN 的ACK。也就是所谓三次握手中的第二次握手。这个设置决定了内核放弃连接之前发送SYN+ACK 包的数量。
net.ipv4.tcp_syn_retries = 1
在内核放弃建立连接之前发送SYN 包的数量。
net.ipv4.tcp_fin_timeout = 1
如 果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2 状态的时间。对端可以出错并永远不关闭连接,甚至意外当机。缺省值是60 秒。2.2 内核的通常值是180 秒,3你可以按这个设置,但要记住的是,即使你的机器是一个轻载的WEB 服务器,也有因为大量的死套接字而内存溢出的风险,FIN- WAIT-2 的危险性比FIN-WAIT-1 要小,因为它最多只能吃掉1.5K 内存,但是它们的生存期长些。
net.ipv4.tcp_keepalive_time = 30
当keepalive 起用的时候,TCP 发送keepalive 消息的频度。缺省是2 小时。

16. 规范使用认证

以设置URL用户登陆认证为例,

1.在线创建用户和密码

2.将生成的内容保存成.htpasswd 文件。例如:passwd.htpasswd

 

3.在访问目录下auth_basic和auth_basic_user_file两项配置:

location /logs {
auth_basic “secret”;
auth_basic_user_file F:/nginx-1.12.1/conf/passwd.htpasswd; //第二步保存的文件位置
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
limit_rate_after 10m;
limit_rate 10k;
alias H:/logs; #虚拟目录
}

 

17.限制访问速率和最大并发连接数模块limit ,可有效的防止ddos攻击。

$binary_remote_addr:客户端变量。限制同一用户的IP地址,可以连接多少个

$server_name:服务器端变量。限制同一server,可以连接多少次

先在nginx.conf里的http{}里加上如下代码:

limit_conn_log_level error;  //超过连接限制后产生错误日志
limit_conn_status 503; //超过连接限制后返回错误503  
limit_conn_zone $binary_remote_addr zone=perip:10m; //设置一个缓存区保存不同key的状态,大小10m。使用$binary_remote_addr来作为key,以此限制每个源IP的链接数
limit_conn_zone $server_name zone=perserver:10m; 
limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;  //每秒钟不超过10个请求
然后在需要限制并发数和下载带宽的网站配置location{}里加上如下代码:  
limit_conn perip 20;  //最大并发连接数20
limit_conn perserver 100; //该服务提供的总连接数不得超过1000

limit_req zone=one burst=5 nodelay; //burs最大延迟请求数量不大于5。使用了nodeley后, 如果burst>5,服务器会立刻返回503状态码。如果没有 nodelay字段会造成大量的tcp连接请求等待。

 

限制下载速度,前100M不限速,后面速度为1M/S

location /download { 
 limit_rate_after 100m; 
 limit_rate 1m; 
 }

18. 禁止恶意域名解析,禁止通过IP访问本站

在server{}段找到:

server_name _;

在其下面添加:

return 500;

这样的话,当使用ip访问时就会返回一个500错误页面。

 

19. 最大优化server_name,location,rewrite3个标签段的设置

这个话题太大了,有时间再整理出来

 

20.其他一些有用的配置优化

location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {

定义用户浏览器缓存的时间为1天,如果静态页面不常更新,可以设置更长,这样可以节省带宽和缓解服务器的压力

}
 
location ~* \.(txt|doc)$ {
 if (-f $request_filename) {
 root /var/www/wordpress/files;

#可以重定向到某个URL,禁止访问*.txt和*.doc文件

break;

 

location ~ ^/test/ {

deny 192.168.1.1;

allow 192.168.1.0/24;

allow 127.0.0.1;

#限制网站来源IP访问