Jusene's Blog

nginx服务优化

字数统计: 3.5k阅读时长: 13 min
2017/04/16 Share

nginx基本安全优化

隐藏nginx版本信息

现在许多漏洞扫描都是在根据软件版本针对性的进行渗透,如果我们可以不让软件版本公布于互联网,可以减少服务器被恶意渗透的概率,而nginx的隐藏自己的版本号也是很简单。

1
~]#curl -I 127.0.0.1
2
HTTP/1.1 200 OK
3
Server: nginx/1.9.12                      我们可以很轻松就得到nginx的版本号
4
Date: Thu, 13 Apr 2017 05:19:56 GMT
5
Content-Type: text/html
6
Content-Length: 7
7
Last-Modified: Sat, 25 Mar 2017 07:53:32 GMT
8
Connection: keep-alive
9
ETag: "58d621fc-7"
10
Accept-Ranges: bytes

如果我们想要去掉这个版本号显示,可以在server端加入server_tokens参数:

1
~]#cat nginx.conf
2
http
3
{
4
	...
5
	server_tokens off;
6
	...
7
}
8
9
~]#curl -I 127.0.0.1
10
HTTP/1.1 200 OK
11
Server: nginx                           这样就没有了nginx的版本号了
12
Date: Thu, 13 Apr 2017 05:24:19 GMT
13
Content-Type: text/html
14
Content-Length: 7
15
Last-Modified: Sat, 25 Mar 2017 07:53:32 GMT
16
Connection: keep-alive
17
ETag: "58d621fc-7"
18
Accept-Ranges: bytes

掩藏nginx软件及版本号

虽然我们隐藏了版本号,但是只要是nginx显示着,恶意人员总可以进行猜测你的版本号是哪个版本之前的,并进行测试渗透,所以为了给黑客增加更大的难度,我们把原来的nginx也改掉。

nginx有在国内有两个比较流行的分支:tengine,openresty

所以这里我想把原生的nginx伪装成这两个分支,修改nginx的软件名,我们需要在未编译前修改源码包,然后重新编译。

依次修改3个nginx源码文件

  1. nginx-1.9.12/src/core]#vim nginx.h
    #define NGINX_VERSION “2.2.3”
    #define NGINX_VER “openresty/“ NGINX_VERSION
    #define NGINX_VAR “openresty”

  2. nginx-1.9.12/src/http]#vim ngx_http_header_filter_module.c
    49 static char ngx_http_server_string[] = “Server: openresty” CRLF;

  3. nginx-1.9.12/src/http]#vim ngx_http_special_response.c

    1
    static u_char ngx_http_error_full_tail[] =
    2
    "<hr><center>" NGINX_VER "</center>" CRLF
    3
    "</body>" CRLF
    4
    "</html>" CRLF
    5
    ;
    6
    7
    8
    static u_char ngx_http_error_tail[] =
    9
    "<hr><center>openresty</center>" CRLF
    10
    "</body>" CRLF
    11
    "</html>" CRLF

    测试:

    1
    ~]#curl -I 127.0.0.1
    2
    HTTP/1.1 200 OK
    3
    Server: openresty/2.2.3
    4
    Date: Thu, 13 Apr 2017 05:52:36 GMT
    5
    Content-Type: text/html
    6
    Content-Length: 612
    7
    Last-Modified: Thu, 13 Apr 2017 05:51:23 GMT
    8
    Connection: keep-alive
    9
    ETag: "58ef11db-264"
    10
    Accept-Ranges: bytes

    更改nginx服务的默认用户

我们都清楚服务进程不得以root权限启动,虽然已root权限启动进程可以使我们配置起来相当便捷,但是这样的结果即是服务被劫持,黑客将获得的是最高服务器权限。

nginx修改worker进程属主数组有两种方法:

  1. 直接在编译的时候指明 –user=nginx –group=nginx
  2. 在nginx.conf中指明 user nginx nginx;

nginx创建建议 useradd -s /sbin/nologin -M nginx

根据参数优化nginx服务性能

优化worker进程个数

nginx采用的是master/worker的工作模式;master是为了管理worker进程,而真正工作的是worker进程。

worker进程个数,一般来说是服务器cpu的个数,多了也起不到任何效果,因为一个cpu在一个时间段只能完成一个任务。

查看cpu的核心数:

1
~]# grep -c processor /proc/cpuinfo
2
2
3
~]# lscpu
4
]#lscpu
5
Architecture:          x86_64
6
CPU op-mode(s):        32-bit, 64-bit
7
Byte Order:            Little Endian
8
CPU(s):                2
9
...

我们修改下nginx.conf的worker进程数。

1
~]# cat nginx.conf
2
...
3
worker_processes 2;
4
...
5
6
低版本不支持,近来的版本也支持auto选项。
7
~]# cat nginx.conf
8
...
9
worker_processes auto;
10
...

auto选项也跟官方建议的一样,按照cpu个数来设定worker进程数,我设置的是auto,我们看下进程的个数:

1
]#ps aux | grep nginx
2
root     28542  0.0  0.0  45392  1880 ?        Ss   13:52   0:00 nginx: master process ./nginx
3
nginx    28899  0.0  0.1  45812  1988 ?        S    14:36   0:00 nginx: worker process
4
nginx    28900  0.0  0.1  45812  1988 ?        S    14:36   0:00 nginx: worker process
5
root     28904  0.0  0.0 112648   972 pts/0    S+   14:36   0:00 grep --color=auto nginx

优化绑定nginx进程绑定到不同的cpu上

进程工作在哪个cpu上是内核分配的,这就会导致一个cpu很忙,一个cpu很闲,计算资源是宝贵的,为了保证cpu充分得到利用,我们可以调整worker进程绑定到不同的cpu上。

worker_cpu_affinity就是配置nginx进程与cpu亲和力的参数,即是把不同的进程分给不同的cpu上。

1
~]# cat nginx.conf
2
...
3
worker_cpu_affinity 0001  0010;
4
...

nginx事物处理模型优化

httpd的MPM有三种模型,而nginx其实没什么可选择的,在linux下使用epoll的I/O多路复用模型,在Freebsd中使用kqueue的I/O多路复用模型,在solaris中使用/dev/poll方式I/O多路复用模型,在windows中使用icop。

1
~]#cat nginx.conf
2
...
3
event {
4
	...
5
	use epoll;
6
	...
7
}
8
...

对于nginx来说,支持的工作模式有select,poll,kqueue,epoll,rtsig和/dev/poll,其中select和poll都是标准的工作模式,kqueue和epoll是高效工作模式,在centos来说,推荐使用epoll,这是高性能高并发的设置。

调整nginx单个worker进程的最大连接数

worker_connection 的值根据具体服务器的性能和程序的内存使用情况来指定。

1
~]#cat nginx.conf
2
...
3
event {
4
	...
5
	worker_connections 20480;
6
	...
7
}
8
...

worker_connections用来设置一个worker process支持的最大并发连接数,这个连接包括所以连接,例如:代理服务器,客户端的连接等,实际并发连接数除了收worker_connections参数控制外,还和最大打开文件数worker_rlimit_nofile有关,nginx的总并发连接数=worker数量 x worker_connections。

调整nginx worker进程最大打开文件数

调整nginx打开的最大文件数,为什么说nginx的最大并发连接数还会受到这个参数的限制呢?因为每个打开的并发连接都是需要一个文件句柄的,当没有文件句柄的时候,这个连接也将无法建立。这里设置了worker进程可以打开最大的文件数,但是这个参数还受到系统打开最大文件数的限制,可以使用‘ulimit -HSn 65535’来临时设置系统打开的最大文件数。

1
~]#cat nginx.conf
2
...
3
worker_rlimit_nofile 65535;
4
...

优化服务器域名散列表的大小

nginx的域名匹配规则,首先是精确匹配,再是左侧通配匹配,而后是右侧通配匹配,最后才是正则通配匹配。

如果定义了大量的域名或者定义太长的域名,我们需要调节http配置中的server_names_hash_max_size和server_names_hash_bucket_size的值。

如果定义了太长的域名会出现:

1
could not build the server_names_hash,
2
you should increase server_names_hash_bucket_size: 32

出现这样的情况我们需要增加server_names_hash_bucket_size的值。

如果定义了太多的域名,会得到一个另一个错误信息:

1
could not build the server_names_hash,
2
you should increase either server_name_hash_max_size: 512
3
or server_names_hash_bucket_size: 32

首先增加server_names_hash_max_size;如果启动不了,或者启动缓慢,则再增加server_names_names_hash_bucket_size的值。

开启高效文件传输模式

sendfile参数开启文件高效传输模式,简单来说就是在内核空间直接构建响应报文,而不通过用户空间构建再返回到内核空间在通过内核tcp协议栈发送给客户端。

sendfile打开的同时也打开了tcp_nopush和tcp_nodelay的功能,可以防止网络或磁盘的I/O堵塞,提升nginx的效率。

1
sendfile on;
2
tcp_nopush on;
3
tcp_nodelay on;

tcp_nopush作用是将http的响应报文的头部信息和文件的开始部分发在一个文件中发布,可以减少网络报文段的数量。
tcp_nodelay作用是当数据发送的时候,内核并不会立刻发送,需要等待更多的字节组成一个数据包,这样可以提高网络I/O的性能,但是业务数据较少的时候的启用tcp_nodelay可能会导致等待时间过长。

优化nginx连接超时时间

nginx连接超时设置keepalive_timeout是为了保持持久连接的参数,有利有弊,当访问量较少的时候,这个参数的设置是可以较少服务开销,加快访问数据的,而当访问量巨大的时候,这个参数设置的过大,则会导致新连接等待,因为一个nginx的访问量是有限的,旧连接不退出,新连接就不会建立。

1
keepalive_timeout 65s;[default 75s]

client_header_timeout 此处可以设置为15s,默认是60s,设置这个值的好处是,客户端发送请求报文头部,如果15s还没发完请求头部,服务器就返回‘Request time out(408)’错误,设置个超时值,可以防止客户端理由http协议进行攻击。

client_body_timeout 用于读取客户端请求主体的超时时间,默认60s,这个参数是两次成功读取请求操作之间的一个超时,而不是读取整个主体的超时时间。

send_timeout 用于指定客户端在这个时间端内,客户端没有任何活动,nginx就关闭连接,默认60s。

上传文件的大小限制

client_max_body_size 8m; 默认1m,一般情况下只有post方法在提交数据时才会携带请求信息。

设置这个值允许最大客户端请求主体大小,在请求头域有‘Content-Length’,如果超过了此配置值,客户端会收到一个413错误,意思请求条目过大,设置0表示禁止检查客户端请求主体大小,此参数对提高服务器安有一定作用。

Fastcgi参数优化

首先我们需要知道整个LNMP的结构,我们才可以对fastcgi的配置进行优化。

  1. fastcgi_connect_timeout:表示nginx服务器与fastcgi服务器连接的超时时间,默认60秒。
  2. fastcgi_send_timeout:设置nginx允许fastcgi服务器端返回的数据超时时间,即在规定时间内后端服务器必须传完所以数据,默认值60秒。
  3. fastcgi_read_timeout:设置nginx允许fastcgi服务器端读取响应信息的超时时间,表示连接成功后,nginx等待后端服务器响应的时间。
  4. fastcgi_buffer_size:这是nginx fastcgi的缓冲区大小的参数,设定用来读取从fastcgi服务器端收到的第一部分响应信息的缓冲区大小,这个参数由fastcgi_buffers来指定一个缓冲区大小。
  5. fastcgi_buffers:指定本地需要多少或多大的缓冲区来缓冲fastcgi的应答请求,指定方式 4 64k这样的格式。
  6. proxy_busy_buffers_size:用于系统繁忙时proxy_buffers的大小。
  7. fastcgi_busy_buffers_size:用于设定系统繁忙时fastcgi_buffers的大小。
  8. fastcgi_temp_file_write_size:fastcgi临时文件的大小。
  9. fastcgi_cache zone | off:是否启用cache,如果启用,数据缓存于哪个cache中
  10. fastcgi_cache_key string:定义要使用的缓存键
  11. fastcgi_cache_method GET | HEAD | POST …:缓存哪些类型的请求的相关数据
  12. fastcgi_cache_min_user number:表示请求几次后被缓存
  13. fastcgi_cache_vaild [code…] time:定义对不同响应码设置不同缓存时间
  14. fastcgi_cache_path path [levels=levels] [use_temp_path=on|off] keys_zone=name:size [inactive=time] [max_size=size] [manager_files=number] [manager_sleep=time] [manager_threshold=time] [loader_files=number] [loader_sleep=time] [loader_threshold=time] [purger=on|off] [purger_files=number] [purger_sleep=time] [purger_threshold=time];
    path:文件系统路径,用于存储缓存的文件数据
    max_size=size: 定义此路径下的多大空间用于存储管理
    levels=#[:#[:#]]:缓存目录层级定义 levels=1:2
    keys_zone=name:size:内存中用于缓存k/v映射关系的空间名称及大小
    inactive=time

注意调用缓存时,至少应该指定三个参数:

  • fastcgi_cache
  • fastcgi_cache_key
  • fastcgi_cache_vaild

gzip压缩实现性能优化

nginx gzip提供了压缩文件内容的功能,需不需要压缩也需要看对象:

  • 纯文本文件压缩比高,因此纯文本最好都压缩,例如:html,js,css,xml,shtml等格式的文件。
  • 被压缩的纯文本文件必须大于1kb,由于压缩算法的缘故,极小的文件压缩kennel会更大。
  • 图片,视频等文件不要压缩,因为这些文件一般都是经过压缩的,压缩不了多少,而且浪费cpu和内存。

压缩配置参数:

1
gzip on;
2
开启gzip压缩
3
gzip_min_length 1k;
4
设置允许压缩的页面最小字节数
5
gzip_buffers 4 16k;
6
压缩缓冲区大小
7
gzip_http_version 1.1;
8
压缩http版本
9
gzip_comp_level 9;
10
压缩比率
11
gzip_types text/html text/javascript text/xml text/css application/x-javascript;
12
指定压缩的mine的类型

expires缓存实行性能优化

网站中css,js,图片等网站元素更改的机会很少,会使客户的浏览器本地缓存下这些数据,而后下次打开的时候不需要重写下载这些元素。

配置实例:

1
location ~ .*\.(gif|png|jpeg|swf) {
2
	expires 365d;
3
}

网站防止盗链

网站中资源被外部网站恶意盗用,如果正在使用cdn,这些资源被频繁的使用,也是一笔不小的流量费。

定义合法的引用
vaild_referers none | blocked | server_name | string …

定义合法的referer数据

none:请求报文的首部没有referer首部
blocked:请求报文的referer首部没有值
server_names: 其值是主机名
arbitrary string: 直接字符串,可以使用*作为通配符
regular expression:被指定的正则的表达式模式匹配到的字符串;要使用~开头

if($invaild_referer)
return 403
}

nginx防爬虫优化

Roboot协议(也称爬虫协议,机器人协议),网站通过Roboot协议告诉搜索引擎哪些可以被爬取,哪些不可以被爬取。

如我们可以看下淘宝的reboot协议: www.taobao.com/robots.txt

爬虫优化配置,我们可以通过$http_user_agent来指定爬虫:

1
if ($http_user_agent ~* "baiduspider|googlebot|sougou web spider") {
2
	return 403;
3
}

控制nginx并发连接数量

  1. limit_conn_zone参数
    语法:limit_conn_zone key zone=name:size
    用于设置共享内存空间,key可以是字符串,nginx自带变量$binary_remote_addr,$server_name。
  2. limit_conn zone number;
    用于指定key设置最大连接数,当超过最大连接数,返回503.

限制单ip的最大连接数:

1
http {
2
...
3
limit_conn_zone $binary_remote_addr zone=addr:zone;
4
...
5
}
6
7
location {
8
	limit_conn addr 1;  限制单ip的并发连接数为1
9
10
}
CATALOG
  1. 1. nginx基本安全优化
    1. 1.1. 隐藏nginx版本信息
    2. 1.2. 掩藏nginx软件及版本号
    3. 1.3. 更改nginx服务的默认用户
  2. 2. 根据参数优化nginx服务性能
    1. 2.1. 优化worker进程个数
    2. 2.2. 优化绑定nginx进程绑定到不同的cpu上
    3. 2.3. nginx事物处理模型优化
    4. 2.4. 调整nginx单个worker进程的最大连接数
    5. 2.5. 调整nginx worker进程最大打开文件数
    6. 2.6. 优化服务器域名散列表的大小
    7. 2.7. 开启高效文件传输模式
    8. 2.8. 优化nginx连接超时时间
    9. 2.9. 上传文件的大小限制
    10. 2.10. Fastcgi参数优化
    11. 2.11. gzip压缩实现性能优化
    12. 2.12. expires缓存实行性能优化
    13. 2.13. 网站防止盗链
    14. 2.14. nginx防爬虫优化
    15. 2.15. 控制nginx并发连接数量