nginx

功能点

  • gzip压缩优化
  • expires缓存优化
  • 网络IO事件模型优化
  • 隐藏软件名称和版本号
  • 防盗链优化
  • 禁止恶意域名解析 【设置server_name】
  • 禁止通过IP地址访问网站
  • HTTP请求方法优化
  • 防DOS攻击单IP并发连接的控制,与连接速率控制
  • 严格设置web站点目录的权限
  • 将nginx进程以及站点运行于监牢模式
  • 通过robot协议以及HTTP_USER_AGENT防爬虫优化
  • 配置错误页面根据错误码指定网页反馈给用户
  • nginx日志相关优化访问日志切割轮询,不记录指定元素日志、最小化日志目录权限
  • 限制上传到资源目录的程序被访问,防止木马入侵系统破坏文件
  • FastCGI参数buffer和cache配置文件的优化
  • php.ini和php-fpm.conf配置文件的优化
  • 有关web服务的Linux内核方面深度优化(网络连接、IO、内存等)
  • nginx加密传输优化(SSL)
  • web服务器磁盘挂载及网络文件系统的优化
  • 使用nginx cache

gzip

#on | off 打开/关闭 
gzip  on;

# 设置用于处理请求压缩的缓冲区数量和大小。比如 32 4K表示按照内存页(one memory page)大小以4K为单位(即一个系统中内存页为4K),申请32倍的内存空间。建议此项不设置,使用默认值。 
gzip_buffers  32 4K;  

#压缩级别,1-10,数字越大压缩的越好,时间也越长,该值的合理取值需要测试
gzip_comp_level  1;  

#通过表达式,表明哪些UA头不使用gzip压缩
gzip_disable "MSIE [1-6].";

#用于识别http协议的版本,早期的浏览器不支持gzip压缩,用户会看到乱码,所以为了支持前期版本加了此选项。默认在http/1.0的协议下不开启gzip压缩
gzip_http_version 1.1;

#当返回内容大于此值时才会使用gzip进行压缩,以K为单位,当值为0时,所有页面都进行压缩
gzip_min_length 20;  

#Nginx做为反向代理的时候启用: 
# off – 关闭所有的代理结果数据压缩
# expired – 如果header中包含”Expires”头信息,启用压缩
# no-cache – 如果header中包含”Cache-Control:no-cache”头信息,启用压缩
# no-store – 如果header中包含”Cache-Control:no-store”头信息,启用压缩
# private – 如果header中包含”Cache-Control:private”头信息,启用压缩
# no_last_modified – 启用压缩,如果header中包含”Last_Modified”头信息,启用压缩
# no_etag – 启用压缩,如果header中包含“ETag”头信息,启用压缩
# auth – 启用压缩,如果header中包含“Authorization”头信息,启用压缩
# any – 无条件压缩所有结果数据 
 gzip_proxied off;

#设置需要压缩的MIME类型,如果不在设置类型范围内的请求不进行压缩
gzip_types text/plain application/x-javascript text/css application/xml text/javascript;

# 增加响应头”Vary: Accept-Encoding”
 gzip_vary on;

tips: When using the SSL/TLS protocol, compressed responses may be subject to BREACH attacks.

expires

ngx_http_headers_module允许添加Expires和Cache-Control头字段以及其他任意字段到响应头

location ~ \.(wma|wmv|asf|mp3|mmf|zip|rar|swf|flv)$ {                   root /var/www/upload/;                expires max;        
}
语法:expires [time|epoch|max|pff]
# 24小时后过期
expires    24h;
# 最新更改时间+24小时后过期
expires    modified +24h;
# 每天的15:30过期
expires    @15h30m;
# 
expires    0;
# 指定“Expires”的值为当前服务器时间-1s,即永远过期
expires    -1;
# The

epoch
parameter sets “Expires” to the value “
Thu, 01 Jan 1970 00:00:01 GMT
”, and “Cache-Control” to “
no-cache
”. expires epoch; expires $expires; add_header Cache-Control private;

网络IO事件模型

user www-data;
pid /run/nginx.pid;
#worker_processes用来设置Nginx服务的进程数。推荐是CPU内核数或者内核数的倍数,推荐使用CPU内核数
worker_processes 4;
#默认情况下,Nginx的多个进程有可能跑在某一个CPU或CPU的某一核上,导致Nginx进程使用硬件的资源不均,因此绑定Nginx进程到不同的CPU上是为了充分利用硬件的多CPU多核资源的目的。
worker_cpu_affinity用来为每个进程分配CPU的工作内核,参数有多个二进制值表示,每一组代表一个进程,每组中的每一位代表该进程使用CPU的情况,1代表使用,0代表不使用。所以我们使用worker_cpu_affinity 0001 0010 0100 1000;来让进程分别绑定不同的核上。
worker_cpu_affinity 0001 0010 0100 1000;
#设置毎个进程的最大文件打开数。如果不设的话上限就是系统的ulimit –n的数字,一般为65535
worker_rlimit_nofile 65535;


events {
        #设置事件驱动模型使用epoll。事件驱动模型有select、poll、poll等
        use epoll;
        #设置一个进程理论允许的最大连接数,理论上越大越好,但不可以超过worker_rlimit_nofile的值。还有个问题,linux系统中有个指令open file resource limit,它设置了进程可以打开的文件句柄数量,可以用下面的指令查看你的linux系统中open file resource limit指令的值,cat /proc/sys/fs/file-max
        worker_connections 65535;
        #这个牵扯到《UNIX网络编程》第一卷中提到的“惊群”问题(Thundering herd problem),大致意思是当某一时刻只有一个网络连接到来时,多个睡眠进程会被同时叫醒,但只有一个进程可获得连接,如果每次唤醒的进程数目太多,会影响一部分系统性能。在Nginx服务器的多进程下,就可能出现这个问题,为了解决这个问题,Nginx配置了包含这样一条指令accept_mutex,当其设置为开启的时候,将会对多个Nginx进程接受连接进行序列化,防止多个进程对连接的争抢。当服务器连接数不多时,开启这个参数会让负载有一定程度的降低。但是当服务器的吞吐量很大时,为了效率,请关闭这个参数;并且关闭这个参数的时候也可以让请求在多个worker间的分配更均衡。所以我们设置accept_mutex off
        accept_mutex off;
        multi_accept off;

}

http {

        ##
        # Basic Settings
        ##
#使用开启或关闭是否使用sendfile()传输文件,普通应用应该设为on,下载等IO重负荷的应用应该设为off,因为大文件不适合放到buffer中  
        sendfile on;
#sendfile为on时这里也应该设为on,数据包会累积一下再一起传输,可以提高一些传输效率
        tcp_nopush on;
#小的数据包不等待直接传输。默认为on。
看上去是和tcp_nopush相反的功能,但是两边都为on时nginx也可以平衡这两个功能的使用
        tcp_nodelay on;
#HTTP连接的持续时间。设的太长会使无用的线程变的太多。这个根据自己服务器访问数量、处理速度以及网络状况方面考虑。
        keepalive_timeout 60 50;
#设置Nginx服务器响应客户端的超时时间,这个超时时间只针对两个客户端和服务器建立连接后,某次活动之间的时间,如果这个时间后,客户端没有任何活动,Nginx服务器将关闭连接,将其设置为10s,Nginx与客户端建立连接后,某次会话中服务器等待客户端响应超过10s,就会自动关闭
    client_header_timeout 80;   #指定请求头的超时时间
    client_body_timeout 80;     #指定请求体超时时间
        send_timeout 10s;
#types_hash_max_size影响散列表的冲突率。types_hash_max_size越大,就会消耗更多的内存,但散列key的冲突率会降低,检索速度就更快。types_hash_max_size越小,消耗的内存就越小,但散列key的冲突率可能上升
        types_hash_max_size 2048;
#该指令用于设置Nginx服务器允许的客户端请求头部的缓冲区大小,默认为1KB,此指令的赋值可以根据系统分页大小来设置,分页大小可以用以下命令获取getconf PAGESIZE
        client_header_buffer_size 4k;
#客户端上传的body的最大值。超过最大值就会发生413(Request Entity Too Large)错误。默认为1m,最好根据自己的情况改大一点。
        client_max_body_size 8m;

        include /etc/nginx/mime.types;
        default_type application/octet-stream;

        ##
        # Logging Settings
        ##

        access_log /var/log/nginx/access.log;
        error_log /var/log/nginx/error.log;

        ##
        # Gzip Settings
        ##

        gzip on;
        gzip_disable "msie6";
        gzip_min_length 1024;
        gzip_vary on;
        gzip_comp_level 2;
        gzip_buffers 32 4k;
#开启时,如果客户端浏览器不支持Gzip处理,Nginx服务器将返回解压后的数据,如果客户端浏览器支持Gzip处理,Nginx服务器忽略该指令设置。仍然返回压缩数据。
        gunzip_static on;
        gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;


        ##
        # Virtual Host Configs
        ##

        include /etc/nginx/conf.d/*.conf;
        include /etc/nginx/sites-enabled/*;
}

隐藏软件名称和版本号

nginx.conf
http{
   server_tokens off;
}
php fastcgi.conf 删除nginx_version
fastcgi_paramSERVER_SOFTWARE    nginx/$nginx_version;
  • 编辑头文件,src/core/nginx.h NGINX_VER 和 NGINX_VERSION
  • 编辑模块,src/http/ngx_http_header_filter_module.c ,修改static u_char ngx_http_server_string[] = “Server: nginx” CRLF

防盗链优化

REFERER验证
server{
     location ~* \.(gif|jpg|png|swf|flv)$ {
         # none “Referer”来源头部为空的情况
         # blocked “Referer”不为空,但是里面的值被代理或者防火墙删除了,这些值都不以http://或者https://开头,而是“Referer: XXXXXXX”这种形式
         # “Referer”来源头部包含当前的server_names(当前域名)
         valid_referers none blocked *.uckendo.com;
         if ($invalid_referer) {
           #rewrite ^/ http://uckendo.com/404.jpg;
           return 404;
         }
     }
}
 # listen  8090;   #监听本机的IPV4和IPV6的8090端口,等于listen *:8000
 listen  192.168.0.1:8090; #监听指定地址的8090端口
 listen    Unix:/www/file  #监听unix socket
 worker_processes 8;# 减少了nginx 工作进程在不同cpu上的跳转,减少了CPU对进程的资源分配与回收,因此可以有效的提升nginx服务器的性能
 worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;
 worker_rlimit_nofile 65535; #配置nginx工作进程最大打开文件数
 keepalive_timeout 60;
 client_header_buffer_size 4k;
 open_file_cache max=102400 inactive=20s;
 open_file_cache_valid 30s; #这个是指多长时间检查一次缓存的有效信息。
 open_file_cache_min_uses 1; # 指令中的inactive 参数时间内文件的最少使用次数,如果超过这个数字,文件描述符一直是在缓存中打开的,如上例,如果有一个文件在inactive 时间内一次没被使用,它将被移除。
 server_tokens off;
 sendfile on; #在http、server或者location模块
 sendfile_max_chunk 512k;   #Nginxg工作进程每次调用sendfile()传输的数据最大不能超出这个值,默认值为0表示无限制,可以设置在http/server/location模块中。
 tcp_nopush on;
 tcp_nodelay on;
 client_header_buffer_size 4k;
 open_file_cache max=65535 inactive=60s;
 events {
     worker_connections 65535; 设置单个工作进程最大连接数102400
     accept_mutex on; #优化同一时刻只有一个请求而避免多个睡眠进程被唤醒的设置,on为防止被同时唤醒,默认为off,因此nginx刚安装完以后要进行适当的优化。
     multi_accept on; #打开同时接受多个新网络连接请求的功能。
     use epoll; # Nginx支持众多的事件驱动,比如select、poll、epoll,只能设置在events模块中设置,使用epoll事件驱动,因为epoll的性能相比其他事件驱动要好很多
 }
 http {
     server_tokens off; #在http 模块当中配置,将nginx的版本隐藏
     # 开启gzip
     gzip on;
     # 启用gzip压缩的最小文件,小于设置值的文件将不会压缩
     gzip_min_length 1k;
     # 禁用IE 6 gzip
     gzip_disable "msie6";
     # 是否在http header中添加Vary: Accept-Encoding,建议开启,该头域的主要功能时要告诉客户端数据已经在服务器进行了压缩,默认设置为off
     gzip_vary on;
     #on为开启并检查客户端浏览器是否中吃gzip压缩功能,off为关闭,always一直发送gzip压缩文件,而不检查浏览器是否支持gzip压缩
     gzip_static off | on | always;
     # 在Nginx 服务器作为反向代理的时候有效,用于设置nginx 服务器是否对后端返回的结果进行gzip压缩,off为关闭,any为压缩所有后端服务器返回的数据
     gzip_proxied off | any;
     # gzip 压缩级别,1-10,数字越大压缩的越好,也越占用CPU时间,详细说明 https://serverfault.com/questions/253074/what-is-the-best-nginx-compression-gzip-level
     gzip_comp_level 6;
     # number #指定Nginx服务器需要向服务器申请的缓存空间的个数
     # 指定每个缓存空间的大小,从Nginx 0.7.8开始,默认number * siez的的值为128,其中size取系统中内存页一页的大小,为4k或者8k等
     gzip_buffers 16 64k;
     #压缩版本(默认1.1,前端如果是squid2.5请使用1.0)
     gzip_http_version 1.0 | 1.1;
     # 进行压缩的文件类型。javascript有多种形式。其中的值可以在 mime.types 文件中找到。
     # 由于jpg,jpeg,png本来就是压缩格式,再行压缩只会消耗cpu资源,帮助并不大;为 ttf、otf 和 svg 字体启用 gzip,对其他字体格式进行 gzip 压缩时效果不明显
     gzip_types text/plain text/css application/javascript application/json
                 application/x-javascript text/xml application/xml application/xml+rss
                   text/javascript font/ttf font/otf image/svg+xml;
 }

可以启用基础缓存: proxy_cache_path和proxy_cache、proxy_cache_path用来设置缓存的路径和配置,proxy_cache用来启用缓存。

levels在/path/to/cache/设置了一个两级层次结构的目录。将大量的文件放置在单个目录中会导致文件访问缓慢,所以针对大多数部署,我们推荐使用两级目录层次结构。如果levels参数没有配置,则NGINX会将所有的文件放到同一个目录中

keys_zone设置一个共享内存区,该内存区用于存储缓存键和元数据,有些类似计时器的用途。将键的拷贝放入内存可以使NGINX在不检索磁盘的情况下快速决定一个请求是HIT还是MISS,这样大大提高了检索速度。一个1MB的内存空间可以存储大约8000个key,那么上面配置的10MB内存空间可以存储差不多80000个key

max_size设置了缓存的上限(在上面的例子中是10G)。这是一个可选项;如果不指定具体值,那就是允许缓存不断增长,占用所有可用的磁盘空间。当缓存达到这个上线,处理器便调用cache manager来移除最近最少被使用的文件,这样把缓存的空间降低至这个限制之下

inactive指定了项目在不被访问的情况下能够在内存中保持的时间。在上面的例子中,如果一个文件在60分钟之内没有被请求,则缓存管理将会自动将其在内存中删除,不管该文件是否过期。该参数默认值为10分钟(10m)。注意,非活动内容有别于过期内容。NGINX不会自动删除由缓存控制头部指定的过期内容(本例中Cache-Control:max-age=120)。过期内容只有在inactive指定时间内没有被访问的情况下才会被删除。如果过期内容被访问了,那么NGINX就会将其从原服务器上刷新,并更新对应的inactive计时器

NGINX最初会将注定写入缓存的文件先放入一个临时存储区域, use_temp_path=off命令指示NGINX将在缓存这些文件时将它们写入同一个目录下。我们强烈建议你将参数设置为off来避免在文件系统中不必要的数据

proxy_cache_revalidate指示NGINX在刷新来自服务器的内容时使用GET请求。如果客户端的请求项已经被缓存过了,但是在缓存控制头部中定义为过期,那么NGINX就会在GET请求中包含If-Modified-Since字段,发送至服务器端。这项配置可以节约带宽,因为对于NGINX已经缓存过的文件,服务器只会在该文件请求头中Last-Modified记录的时间内被修改时才将全部文件一起发送

proxy_cache_min_uses设置了在NGINX缓存前,客户端请求一个条目的最短时间。当缓存不断被填满时,这项设置便十分有用,因为这确保了只有那些被经常访问的内容才会被添加到缓存中。该项默认值为1。

proxy_cache_use_stale中的updating参数告知NGINX在客户端请求的项目的更新正在原服务器中下载时发送旧内容,而不是向服务器转发重复的请求。第一个请求陈旧文件的用户不得不等待文件在原服务器中更新完毕。陈旧的文件会返回给随后的请求直到更新后的文件被全部下载

当proxy_cache_lock被启用时,当多个客户端请求一个缓存中不存在的文件(或称之为一个MISS),只有这些请求中的第一个被允许发送至服务器。其他请求在第一个请求得到满意结果之后在缓存中得到文件。如果不启用proxy_cache_lock,则所有在缓存中找不到文件的请求都会直接与服务器通信

proxy_cache_path /path/to/cache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m;
use_temp_path=off;

server{

    location {

        proxy_cache my_cache;

        # proxy_cache_key $proxy_host$request_uri$cookie_jessionid; #使用Cookie作为缓存键的一部分

        proxy_cache_revalidate on;

        proxy_cache_min_uses 3;

        proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;

        proxy_cache_lock on;

        proxy_cache_methods GET HEAD POST;

        proxy_pass http://my_upstream;

    }

    #NGINX会忽略所有/images/下的Cache-Control头。proxy_cache_valid命令强制规定缓存数据的过期时间,如果忽略Cache-Control头,则该命令是十分必要的。NGINX不会缓存没有过期时间的文件。

    loation /images/ {

        proxy_ignore_headers Cache-Control;

        proxy_cache_valid any 30m;

    }

}

nginx提供了$upstream_cache_status这个变量来显示缓存的状态,我们可以在配置中添加一个http头[Nginx-Cache:HIT]来显示这一状态,达到类似squid的效果。

$upstream_cache_status包含以下几种状态:
·MISS 未命中,请求被传送到后端
·HIT 缓存命中
·EXPIRED 缓存已经过期请求被传送到后端
·UPDATING 正在更新缓存,将使用旧的应答
·STALE 后端将得到过期的应答

nginx cache命中率统计

即然nginx为我们提供了$upstream_cache_status函数,自然可以将命中状态写入到日志中。具体可以如下定义日志格式:
log_format main ‘$remote_addr – $remote_user [$time_local] “$request” ‘
‘$status $body_bytes_sent “$http_referer” ‘
‘”$http_user_agent” “$http_x_forwarded_for”‘
‘”$upstream_cache_status”‘;

命中率统计方法:用HIT的数量除以日志总量得出缓存命中率:
awk ‘{if($NF==””HIT””) hit++} END {printf “%.2f%”,hit/NR}’ access.log
了解了原理以后,也可以通过crontab脚本将每天的命中率统计到一个日志中,以备查看。
1 0 * * * /opt/shell/nginx_cache_hit >> /usr/local/nginx/logs/hit
访脚本的内容为:
LOG_FILE=’/usr/local/nginx/logs/access.log.1′
LAST_DAY=$(date +%F -d “-1 day”)
awk ‘{if($NF==””HIT””) hit++} END {printf “‘$LAST_DAY’: %d %d %.2f%n”, hit,NR,hit/NR}’ $LOG_FILE

LOG_FILE=’/usr/local/nginx/logs/access.log.1′
LAST_DAY=$(date +%F -d “-1 day”)
awk ‘{if($NF==””HIT””) hit++} END {printf “‘$LAST_DAY’: %d %d %.2f%n”, hit,NR,hit/NR}’ $LOG_FILE

NGINX 如何处理字节范围请求?

如果缓存中的文件是最新的,NGINX会对客户端提出的字节范围请求传递指定的字节。如果文件并没有被提前缓存,或者是陈旧的,那么NGINX会从服务器上下载完整文件。如果请求了单字节范围,NGINX会尽快的将该字节发送给客户端,如果在下载的数据流中刚好有这个字节。如果请求指定了同一个文件中的多个字节范围,NGINX则会在文件下载完毕时将整个文件发送给客户端。 一旦文件下载完毕,NGINX将整个数据移动到缓存中,这样一来,无论将来的字节范围请求是单字节还是多字节范围,NGINX都可以在缓存中找到指定的内容立即响应。

Leave Comment

电子邮件地址不会被公开。 必填项已用*标注