- 隐藏版本号
- 使用程序用户
- worker进程优化
- 事件处理模型及最大连接数
- 文件高效传输
- 超时时间
- 上传文件大小限制
- 压缩优化
- 缓存优化
- 访问控制
- 禁止访问单个目录的命令
location ~ ^/static
{
deny all;
}
#禁止访问多个目录的命令如下:
location ~ ^/(static|js)
{
deny all;
} - 防盗链
- http://www.yunjisuan.com/img/nolink.jpg;
}
}
#提示:要根据自己公司的实际业务(是否有外链的合作)进行域名设置。">下面的代码为利用referer且针对扩展名rewrite重定向,即实现防盗链的Nginx配置。
location ~ .(jpg|gif|png|swf|flv|wma|wmv|asf|mp3|mmf|zip|rar)$
{
valid_referers none blocked .yunjisuan.com yunjisuan.com; #
if ($invalid_referer)
{
rewrite ^/ http://www.yunjisuan.com/img/nolink.jpg;
}
}
#提示:要根据自己公司的实际业务(是否有外链的合作)进行域名设置。 - NginxHttpAccessKeyModule实现防盗链
- 水印防盗链
- 错误页面的优雅展示
- 限制HTTP的请求方法
- 并发连接数量控制
- 客户端请求速率
- 小结文档:
未作特殊说明的都是默认配置文件带的参数
隐藏版本号
1、配置修改
http
{
……………
server_tokens off; #默认开启on
……………
}
2、源码修改
/usr/src/nginx-1.18.0/src/core/nginx.h #文件内容很少很容易改
/usr/src/nginx-1.18.0//src/http/ngx_http_header_filter_module.c #大概49行,关键字Server: nginx
/usr/src/nginx-1.18.0/src/http/ngx_http_special_response.c #大概20-30行
static u_char ngx_http_error_full_tail[] =
“
““ CRLF
““ CRLF
;
static u_char ngx_http_error_build_tail[] =
“
““ CRLF
然后开始编译安装的
使用程序用户
1 ./configure的时候指定用户—user
2 nginx.conf指定user nobody; (默认) 修改为程序用户www (useradd -M -s /sbin/nologin www)
worker进程优化
进程数量优化
worker_processes 2; #指定了Nginx要开启的进程数,结尾数字就是进程个数
查看CPU总核数方法
一颗cpu的核数
grep processor /proc/cpuinfo
grep “physical id” /proc/cpuinfo
绑定进程到cpu上
worker_processes 4;
worker_cpu_affinity 0001 0010 0100 1000;
#这种配置方法是平均分配的
#若要绑定到某颗CPU上,比如CPU3(cpu的id排序从0开始),为1000,那么应该都写成1000的值
#八核则是 00000001
#这里推荐一个压测命令webbench,-c 指定并发数 -t 指定时间(默认秒)
#例:webbench -c 1000 -t 60 http://www.yjs.com/(最后的/不能省略)
事件处理模型及最大连接数
Nginx的连接处理机制在不同的操作系统会采用不同的额I/O模型
在Linux下,Nginx使用epoll的I/O多路复用模型;在Freebsd中使用kqueue的I/O多路复用模型;在Solaris中使用/dev/poll方式的I/O多路复用模型;在Windows中使用的是icop,等等。
要根据系统类型选择不同的事件处理模型,可供使用的选择有“use [kqueue|rtsig|epoll|/dev/poll|select|poll];”
use是一个事件模块指令,用来指定Nginx的工作模式。
Nginx支持的工作模式有select,poll,kqueue,epoll,rtsig和/dev/poll。
其中select和poll都是标准的工作模式
kqueue和epoll是高效的工作模式
不同的是epoll用在Linux平台上,而kqueue用在BSD系统中。
对于Linux系统Linux2.6+内核,推荐选择epoll工作模式,这是高性能高并发的设置
处理模型应用配置应在events中设置
我们知道,events中还设置了最大连接数
events {
use epoll;
worker_connections 1024;
}
实际的并发连接数除了受worker_connections参数控制外,还和最大打开文件数worker_rlimit_nofile有关
worker_rlimit_nofile 65535; #没有明确放置位置,那就放在总配置文件架构里
Nginx总并发连接=worker数量*worker_connections
参考资料:
http://nginx.org/en/docs/ngx_core_module.html
Linux系统文件最大打开数设置:ulimit -n 65535(临时),永久生效方法在我的k8s搭建中有做过了
文件高效传输
sendfile参数用于开启文件的高效传输模式。
同时将tcp_nopush和tcp_nodelay两个指令设置为on,可防止网络及磁盘I/O阻塞,提升Nginx工作效率。
tcp_nopush
激活或禁用Linux上的TCP_CORK socket选项
此选项仅仅当开启sendfile时才生效
激活这个tcp_nopush参数可以允许把http response header和文件的开始部分放在一个文件里发布,其积极的作用是减少网络报文段的数量
tcp_nodelay
默认情况下当数据发送时,内核并不会马上发送,可能会等待更多的字节组成一个数据包,这样可以提高I/O性能
但是,在每次只发送很少字节的业务场景中,使用tcp_nodelay功能,等待时间会比较长
激活或禁用TCP_NODELAY选项,当一个连接进入keep-alive状态时生效
超时时间
keepalive_timeout 60; #客户端连接保持会话的超时时间
client_header_timeout 15; #用于设置读取客户端请求头数据的超时时间
client_body_timeout 15; #用于设置读取客户端请求主体的超时时间,若在时间范围内客户端没有发送任何数据,将返回“Request time out(408)”错误
send_timeout 25; #用于指定响应客户端的超时时间
上传文件大小限制
client_max_body_size 8m; #设置为0表示禁止检查客户端请求主体大小
压缩优化
gzip压缩实现性能优化
gzip on;#开启gzip压缩功能
gzip_min_length 1k;
#设置允许压缩的页面最小字节数,页面字节数从header头的Content-Length中获取。默认值0,表示不管页面多大都进行压缩。建议设置成大于1K,如果小于1K可能会越压越大。
gzip_buffers 4 16K;
#压缩缓冲区大小。表示申请4个单位为16K的内存作为压缩结果流缓存,默认值是申请与原始数据大小相同的内存空间来存储gzip压缩结果。
gzip_http_version 1.1;
#压缩版本(默认1.1,前端为squid2.5时使用1.0),用于设置识别HTTP协议版本,默认是1.1,目前大部分浏览器已经支持GZIP解压,使用默认即可。
gzip_comp_level 2;
#压缩比率。用来指定gzip压缩比,1压缩比最小,处理速度最快;9压缩比最大,传输速度快,但处理最慢,也比较消耗CPU资源。
gzip_types text/plain application/x-javascript text/css application/xml;
#用来指定压缩的类型,“text/html”类型总是会被压缩,这个就是HTTP原理部分讲的媒体类型。
gzip_vary on;
#vary header支持。该选项可以让前端的缓存服务器缓存经过gzip压缩的页面,例如用Squid缓存经过Nginx压缩的数据。
缓存优化
简单说,Nginx expires的功能就是为用户访问的网站内容设定一个过期时间,当用户第一次访问这些内容时,会把这些内容存储在用户浏览器本地,这样用户第二次及以后继续访问该网站时,浏览器会检查加载已经缓存在用户浏览器本地的内容,就不会去服务器下载了,直到缓存的内容过期或被清除位置。
更深入的理解:expires的功能就是允许通过Nginx配置文件控制HTTP的“Expires”和“Cache-Control”响应头部内容,告诉客户端浏览器是否缓存和缓存多久以内访问的内容。这个expires模块控制Nginx服务器应答时的expires头内容和Cache-Control头的max-age指令。缓存的有效期可以设置为相对于源文件的最后修改时刻或客户端的访问时刻。
这些HTTP头向客户端表明了额内容的有效性和持久性。如果客户端本地有内容缓存,则内容就可以从缓存而不是从服务器中读取,然后客户端会检查缓存中的副本,看其是否过期或失效,以决定是否重新从服务器获得内容更新。
在网站的开发和运营中,视频,图片,CSS,JS等网站元素的更改机会较少,特别是图片,这时可以将图片设置在客户浏览器本地缓存365天或3650天,而将CSS,JS,html等代码缓存10~30天。这样用户第一次打开页面后,会在本地的浏览器按照过期日期缓存相应的内容,下次用户再打开类似的页面时,重复的元素就无需下载了,从而加快用户访问速度。用户的访问请求和数据减少了,也可节省大量的服务器端带宽。此功能同Apache的expires功能类似。
expires可以降低网站的带宽,节约成本。
加快用户访问网站的速度,提升用户访问体验。
服务器访问量降低了,服务器压力就减轻了,服务器成本也会降低,甚至可以节约人力成本。
对于几乎所有的Web服务来说,这是非常重要的功能之一,Apache服务也有此功能
根据文件扩展名
location ~ ..(gif|jpg|jpeg|png|bmp|swf)$
{
expires 3650d;
}
该范例的意思是当用户访问网站URL结尾的文件扩展名为上述指定类型的图片时,设置缓存3650天,即10年
location ~ ..(js|css)$
{
expires 30d;
}
该范例的意思是当用户访问网站URL结尾的文件扩展名为js,css类型的元素时,设置缓存30天,即1个月
根据URL中的路径(目录)
location ~ ^/(images|javascript|js|css|flash|media|static)/
{
expires 360d;
}
该范例的意思是当用过户访问网站URL中包含上述路径(例:images,js,css,这些在服务器端是程序目录)时,把访问的内容设置缓存360天,即1年。
可通过火狐浏览器+firebug插件+yslow插件查看gzip压缩及expires缓存结果。提前安装好yslow插件,开启监控,然后打开LNMP时安装的博客地址,就可以看到如下图所示的压缩结果
在Linux客户端可通过如下curl命令查看图片URL的缓存header信息:
[root@localhost ~]# curl -I www.yjs.com
HTTP/1.1 200 OK
Server: nginx
Date: Wed, 30 Aug 2017 02:15:54 GMT
Content-Type: text/html
Content-Length: 18
Connection: keep-alive
Last-Modified: Tue, 29 Aug 2017 19:37:44 GMT
ETag: “59a5c288-12”
Expires: Sat, 09 Sep 2017 02:15:54 GMT #缓存的过期时间
Cache-Control: max-age=864000 #缓存的总时间,单位秒
Accept-Ranges: bytes
expires的缺点
当网站被缓存的页面或数据更新了,此时用户端看到的可能还是旧的已经缓存的内容,这样就会影响用户体验,那么如何解决这个问题呢?解决方法如下。
第一,对于经常需要变动的图片等文件,可以缩短对象缓存时间,例如:谷歌和百度的首页图片经常根据不同的日期换成一些节日的图,所以这里可以将这个图片设置为缓存期1天。
第二,当网站改版或更新时,可以在服务器将缓存的对象改名(网站代码程序)。
对于网站的图片,附件,一般不会被用户直接修改,用户层面上的修改图片,实际上是重新传到服务器,虽然内容一样但是是一个新的图片名了。
网站改版升级会修改JS,CSS元素,若改版时对这些元素改了名,会使得前端的CDN及用户端需要重新缓存内容。
访问控制
禁止解析指定目录下的指定程序
location ~ ^/images/..(php|php5|sh|pl|py)$
{
deny all;
}
location ~ ^/static/..(php|php5|sh|pl|py)$
{
deny all;
}
location ~ ^/data/(attachment|avatar)/..(php|php5)$
{
deny all;
}
#对上述目录的限制必须写在Nginx处理PHP服务配置的前面
location ~ .*.(php|php5)$
{
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fcgi.conf;
}
禁止访问.txt和.doc文件
location ~ .(txt|doc)$
{
if (-f $request_filename)
{
root /data/www/www;
#rewrite …可以重定向到某个URL
break;
}
}
location ~ .(txt|doc)$
{
root /data/www/www;
deny all;
}
禁止访问指定的单个或多个目录
禁止访问单个目录的命令
location ~ ^/static
{
deny all;
}
#禁止访问多个目录的命令如下:
location ~ ^/(static|js)
{
deny all;
}
禁止访问目录并返回指定的HTTP状态码
server
{
listen 80;
server_name www.yjs.com yjs.com;
root /data/www/www;
index index.html index.htm;
access_log logs/www_access.log commonlog;
location /admin/
{
return 404;
}
location /tmplates/
{
return 403;
}
}
限制网站来源IP访问
下面介绍如何使用ngx_http_access_module限制网站来源IP访问
案例环境:phpmyadmin数据库的Web客户端,内部开发人员用的。
范例1:禁止某目录让外界访问,但允许某IP访问该目录,且支持PHP解析,命令如下:
location ~ ^/yunjisuan/
{
allow 202.111.12.211;
deny all;
}
location ~ .*.(php|php5)$
{
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
}
范例2:限制指定IP或IP段访问,命令如下:
location /
{
deny 192.168.1.1;
allow 192.168.1.0/24;
allow 10.1.1.0/16;
deny all;
}
参考资料:http://nginx.org/en/docs/http/ngx_http_access_module.html
客户端IP限制
企业问题案例: Nginx做反向代理的时候可以限制客户端IP吗?
答:可以,具体方法如下:
方法一:使用if来控制,命令如下:
if ($remote_addr = 10.0.0.7)
{
return 403;
}
if ($remote_addr = 218.247.17.130)
{
set $allow_access_root ‘ture’; #我也不知道什么意思
}
方法二:利用deny和allow只允许IP访问,命令如下:
location / {
root html/blog;
index index.php index.html index.htm;
allow 10.0.0.7;
deny all;
}
方法三:只拒绝某些IP访问,命令如下:
location / {
root html/blog;
index index.php index.html index.htm;
deny 10.0.0.7;
allow all;
}
注意事项:
deny一定要加一个IP,否则会直接跳转到403,不再往下执行了,如果403默认页是在同一域名下,会造成死循环访问。
对于allow的IP段,从允许访问的段位从小到大排列,如127.0.0.0/24的下面才能是10.10.0.0/16,其中:
24表示子网掩码:255.255.255.0
16表示子网掩码:255.255.0.0
8表示子网掩码:255.0.0.0
以deny all:结尾,表示除了上面允许的,其他的都禁止。如:
deny 192.168.1.1;
allow 127.0.0.0/24;
allow 192.168.0.0/16;
allow 10.10.0.0/16;
deny all;
禁止非法域名解析访问企业网站
Nginx如何防止用户IP访问网站(恶意域名解析,也相当于是直接IP访问企业网站)
方法一:让使用IP访问网站的用户,或者恶意解析域名的用过户,收到501错误,命令如下:
server {
listen 80 defaultserver;
server_name ;
return 501;
}
#说明:直接报501错误,从用户体验上不是很好
方法二:通过301跳转到主页,命令如下:
server {
listen 80 defaultserver;
server_name ;
rewrite ^(.) http://www.yunjisuan.com/$1 permanent;
}
方法三:发现某域名恶意解析到公司的服务器IP,在server标签里添加以下代码即可,若有多个server则要多处添加。
if ($host ! ~ ^www.yunjisuan.com$)
{
rewrite ^(.) http://www.yunjisuan.com/$1 permanent;
}
#说明:代码含义为如果header信息的host主机名字非www.yunjisuan.com,就301跳转到www.yunjisuan.com
防盗链
Web服务实现防盗链实战
在默认情况下,只需要进行简单的配置,即可实现防盗链处理。请看下面的实例。
(1)利用referer,并且针对扩展名rewrite重定向
下面的代码为利用referer且针对扩展名rewrite重定向,即实现防盗链的Nginx配置。
location ~ .(jpg|gif|png|swf|flv|wma|wmv|asf|mp3|mmf|zip|rar)$
{
valid_referers none blocked .yunjisuan.com yunjisuan.com; #
if ($invalid_referer)
{
rewrite ^/ http://www.yunjisuan.com/img/nolink.jpg;
}
}
#提示:要根据自己公司的实际业务(是否有外链的合作)进行域名设置。
(2)利用referer,并且针对站点目录过滤返回错误码
针对目录的方法如下:
location /images {
root /data/www/www;
valid_referers none blocked *.yunjisuan.com yunjisuan.com;
if ($invalid_referer) {
return403;
}
}
在上面这段防盗链设置中,分别针对不同文件类型和不同的目录进行了设置,同学们可以根据自己需求进行类似设定。
备注:valid_referers 指令详解
valid_referer none blocked serevr_names string或者是正则表达式
none 代表没有referer
blocked 代表有referer但是被防火墙或者是代理给去除了
string或者正在表达式 用来匹配referer
nginx会通过查看referer字段和valid_referers后面的referer列表进行匹配,如果匹配到了就invalid_referer字段值为0 否则设置该值为1
例:
valid_referers none blocked server_names;
if ($invalid_referer) {
rewrite ^/ http://**.com/ redirect;
}
说明:
1.首先当我输入我要打开的网址的时候,因为是直接输入的没有referer所以匹配了
valid_referers后面的none或者是blocked 所以invalid_referer值为0 所以不进行跳转.
当我是从这个网站里面的链接跳到该网站首页的时候 因为referer的值是肯定包含srever_names 所以匹配了server_names所以不进行跳转.
2.当我从搜素引擎进去的时候因为referer字段类似于www.google.com.hk/search
开始进行匹配 发现没有一个匹配,则此时会设置invalid_referer值为1 if语句成功执行,进行了跳转. 达到功能
NginxHttpAccessKeyModule实现防盗链
如果不怕麻烦,有条件实现的话,推荐使用NginxHttpAccessKeyModule。
其运行方式是:
如download目录下有一个file.zip文件。
对应的URI是http://www.abc.com/download/file.zip
使用ngx_http_accesskey_module 模块后就成了http://www.bac.com/download/file.zipkey=09093abeac094
只有正确地给定了key值,才能下载download目录下的file.zip,而且key值是与用户的IP相关的
这样就可以避免被盗链了
据说,现在NginxHttpAccessKeyModule连迅雷都可以防了
水印防盗链
为图片添加版权水印是很有效的方法。
网站直接转载图片一般是为了快捷,但是对于有水印的图片,很多站长是不愿意转载的。
错误页面的优雅展示
范例1:对错误代码403实行本地页面跳转
server {
listen 80;
server_name www.yunjisuan.com;
location / {
root html/www;
index index.html index.htm;
}
error_page 403 /403.html; #当出现403错误时,会跳转到403.html页面
}
#上面的/403.html是相对于站点根目录html/www的。
范例2:对错误代码404实行本地页面优雅显示
server {
listen 80;
server_name www.yunjisuan.com;
location / {
root html/www;
index index.html index.htm;
error_page 404 /404.html;
#当出现404错误时,会跳转到404.html页面
}
}
#代码中的/404.html是相对于站点根目录html/www的
范例3: 50x页面放到本地单独目录下,进行优雅显示
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /data/www/html;
}
#这里指定单独的站点目录存放到50x.html文件中。
范例4: 错误状态码URL重定向
listen 80;
server_name www.yunjisuan.com;
location / {
root html/www;
index index.html index.htm;
error_page 404 http://bbs.yunjisuan.com;
#当出现404错误时,会跳转到指定的URL http://bbs.yunjisuan.com页面显示给用户,这个URL一般是企业另外的可用地址。
access_log /usr/local/nginx/logs/bbs_access.log commonlog;
}
}
#代码中的/404.html是相对于站点根目录html/www的。
范例5: 将错误状态码重定向到一个location
location / {
error_page 404 = @fallback;
}
location @fallback {
proxy_pass http://backend;
}
限制HTTP的请求方法
在之前的HTTP协议原理一节中,讲解了很多HTTP方法
其中最常用的HTTP方法为GET,POST
我们可以通过Nginx限制HTTP请求的方法来达到提升服务器安全的目的,
例如,让HTTP只能使用GET,HEAD和POST方法的配置如下:
#Only allow these request methods
if ($request_method ! ~ ^(GET|HEAD|POST)$)
{
return 501;
}
当上传服务器上传数据到存储服务器时,用户上传写入的目录就不得不给Nginx对应的用户相关权限
这样一旦程序有漏洞,木马就有可能被上传到服务器挂载的对应存储服务器的目录里
虽然我们也做了禁止PHP,SH,PL,PY等扩展名的解析限制,但还是会遗漏一些想不到的可执行文件
对于这样情况,该怎么办呢?事实上,还可以通过限制上传服务器的Web服务(可以具体到文件)使用GET方法,防止用户通过上传服务器访问存储内容,让访问存储渠道只能从静态或图片服务器入口进入
例如,在上传服务器上限制HTTP的GET方法的配置如下:
#Only deny GET request methods ##
if ($request_method ~* ^(GET)$)
{
return 501;
}
#提示:还可以加一层location,更具体地限制文件名
并发连接数量控制
控制Nginx并发连接数量参数的说明如下:
1)limit_conn_zone参数:
语法:limit_conn_zone key zone=name:size;
上下文:http
#用于设置共享内存区域,key可以是字符串,Nginx自带变量或前两个组合,如$binary_remote_addr,$server_name.name为内存区域的名称,size为内存区域的大小。
2)limit_conn参数:
语法:limit_conn zone number;
上下文:http,server,location
#用于指定key设置最大连接数。当超过最大连接数时,服务器会返回503(Service Temporarily Unavailable)错误
单IP并发连接数
location / {<br /> root html;<br /> index index.html index.htm;<br /> limit_conn addr 1; #限制同IP的并发为1;<br /> }<br />观察日志可以发现,webbench -c指定的并发客户端数量,只有1个是200的
虚拟主机总连接数
location / {<br /> root html;<br /> index index.html index.htm;<br /> #limit_conn addr 1;<br /> limit_conn perserver 2; #设置虚拟主机同一时间一个的连接数为2<br /> }<br />观察日志可以发现,webbench -c指定的并发客户端数量,只有2个是200的
客户端请求速率
https://www.rainng.com/nginx-httplimitreq/
ngx_http_limit_req_module模块用于限制每个IP访问每个定义key的请求速率
语法:limit_req_zone key zone=name: size rate=rate;
上下文1:http
#用于设置共享内存区域,key可以是1字符串,Nginx自带变量或前两个组合,如$binary_remote_addr。name为内存区域的名称,size为内存区域的大小,rate为速率,单位为r/s,每秒一个请求。
limit_req参数说明如下:
语法:limit_req zone=name [burst=number][nodelay];
上下文:http,server,location
这里运用了令牌桶原理,burst=num,一共有num块令牌,令牌发完后,多出来的那些请求就会返回503。
换句话说,一个银行,只有一个营业员,银行很小,等候室只有5个人的位置。因此,营业员一个时刻只能为一个人提供服务,剩下的不超过5个人可以在银行内等待,超出的人不提供服务,直接返回503。
nodelay默认在不超过burst值的前提下会排队等待处理,如果使用此参数,就会处理完num + 1次请求,剩余的请求都视为超时,返回503。
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
#以请求的客户端IP作为key值,内存区域命令为one,分配10m内存空间,访问速率限制为1秒1次请求(request)
# limit_conn_zone $binary_remote_addr zone=addr:10m;
# limit_conn_zone $server_name zone=perserver:10m;
server {
listen 80;
server_name www.yunjisuan.com;
location / {
root html;
index index.html index.htm;
limit_req zone=one burst=5;
#使用前面定义的名为one的内存空间,队列值为5,即可以有5个请求排队等待
# limit_conn addr 1;
# limit_conn addr 1;
}
}
}
#说明:本次测试只成功响应了11个请求,近视1秒处理1个请求。多余的请求一律用503进行响应。
#使用的压测命令是webbench -c 100 -t 10 http://www.yjs.com/