Linux学习系列之Nginx调优实战

Nginx配置文件性能微调

全局的配置

user www-data; 
pid /var/run/nginx.pid; 
worker_processes auto; 
worker_rlimit_nofile 100000; 

worker_process定义了nginx对外提供Web服务时的worker进程数,起始可以设置为CPU的核数,CPU核数是多少就设置为多少(设置为"auto"将自动检测)

worker_rlimit_nofile更改worker进程的最大打开文件限制,如果没设置的话,这个值为操作系统的限制.设置后你的操作系统和Nginx可以处理比"ulimit -a"更多的文件,所以把这个值设高,这样nginx就不会有"too many open files"问题了

Event模块部分

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

worker_connections设置可由一个worker进程同时打开的最大连接数.如果设置了上面提到的worker_rlimit_nofile,我们可以将这个值设得很高

注意:最大客户数也由系统的可用socket连接数限制(~ 64K),所以设置不切实际的高没什么好处

multi_accept告诉nginx收到一个新连接通知后接受尽可能多的连接

use epoll使用epoll模型,效率更高

HTTP模块部分

http { 
   server_tokens off; 
   sendfile on; 
   tcp_nopush on; 
   tcp_nodelay on; 
... 
} 

service_tokens隐藏Nginx版本号

sendfile可以让sendfile()发挥作用.sendfile()可以在磁盘和TCP socket之间互相拷贝数据(或任意两个文件描述符)

默认是Pre-sendfile,传送数据之前在用户空间申请数据缓冲区,之后用read()将数据从文件拷贝到这个缓冲区,write()将缓冲区数据写入网络.sendfile()是立即将数据从磁盘读到OS缓存,sendfile()要比组合read()和write()以及打开关闭丢弃缓冲更加有效

tcp_nopush告诉nginx在一个数据包里发送所有头文件,而不一个接一个的发送

tcp_nodelay告诉nginx不要缓存数据,而是一段一段的发送--当需要及时发送数据时,就应该给应用设置这个属性,这样发送一小块数据信息时就不能立即得到返回值

keepalive_timeout 10; 
client_header_timeout 10; 
client_body_timeout 10; 
reset_timedout_connection on; 
send_timeout 10; 

keepalive_timeout 给客户端分配keep-alive链接超时时间.服务器将在这个超时时间过后关闭链接.我们将它设置低些可以让ngnix持续工作的时间更长

client_header_timeout和client_body_timeout 设置请求头和请求体(各自)的超时时间,在一定时间内收不到客户端的请求头请求体就关闭连接

reset_timedout_connection 告诉nginx关闭不响应的客户端连接.这将会释放那个客户端所占有的内存空间

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

limit_conn_zone $binary_remote_addr zone=addr:5m; 
limit_conn addr 100; 

limit_conn_zone设置用于保存各种key(比如当前连接数)的共享内存的参数.5m就是5兆字节,这个值应该被设置的足够大以存储(32K*5)32byte状态或者(16K*5)64byte状态

limit_conn addr为给定的key设置最大连接数.这里key是addr,我们设置的值是100,也就是说我们允许每一个IP地址最多同时打开有100个连接

include /etc/nginx/mime.types; 
default_type text/html; 
charset UTF-8; 

include只是一个在当前文件中包含另一个文件内容的指令。这里我们使用它来加载稍后会用到的一系列的MIME类型

default_type设置文件使用的默认的MIME-type

charset设置我们的头文件中的默认的字符集

gzip on;
gzip_min_length 1k;      #最小1K的文件才启动压缩
gzip_buffers 4 32k;      #压缩过程都写到buffer里面,压缩完成才发给客户端
gzip_http_version 1.1;
gzip_comp_level 9;       #压缩的级别
gzip_types text/css text/xml application/javascripts;  #对什么样的内容压缩
gzip_vary on;            #让前边的缓存服务器识别压缩后的文件

gzip是告诉nginx采用gzip压缩的形式发送数据,这将会减少我们发送的数据量
gzip_min_length设置对数据启用压缩的最少字节数.如果一个请求小于1K,我们最好不要压缩它,因为压缩这些小的数据会降低处理此请求的所有进程的速度
gzip_buffers 
gzip_http_version是http协议
gzip_comp_level设置数据的压缩等级.这个等级可以是1-9之间的任意数值,9是最慢但是压缩比最大的.我们设置为4,这是一个比较折中的设置
gzip_types设置需要压缩的数据格式
gzip_vary 让前边的缓存服务器识别压缩后的文件

open_file_cache max=100000 inactive=20s; 
open_file_cache_valid 30s; 
open_file_cache_min_uses 2; 
open_file_cache_errors on; 

open_file_cache打开缓存的同时也指定了缓存最大数目,以及缓存的时间.我们可以设置一个相对高的最大时间,这样我们可以在它们不活动超过20秒后清除掉

open_file_cache_valid在open_file_cache中指定检测正确信息的间隔时间

 open_file_cache_min_uses 定义了open_file_cache中指令参数不活动时间期间里最小的文件数

open_file_cache_errors指定了当搜索一个文件时是否缓存错误信息,也包括再次给配置中添加文件.我们也包括了服务器模块,这些是在不同文件中定义的.如果你的服务器模块不在这些位置,你就得修改这一行来指定正确的位置

Nginx expires缓存

介绍

简单的说,nginx expire功能就是为用户访问的访问内容设定一个过期时间,当用户第一次访问到这些内容时,会把这些内容存储在用户浏览器本地,这样用户第二次访问该网站,浏览器会加载检查已经缓存在用户浏览器恩地的内容,就不去服务器下载了

作用

在网站开发和运营中,对于视频、图片、css、js等不长修改的元素缓存在客户浏览器本地.
图片可以缓存365天,css、js、html等代码缓存10-30天,这样用户第一次打开页面后,会按过期时间在客户浏览器缓存上述内容,下次用户在打开页面的时候重复的元素就无需加载了可放位置:

http server location,我们一般放在location段根据匹配规则设置过期时间

配置

location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)${
             expires 3650d;
        }
        location ~ .*\.(js|css)?$ {
             expires 30d;
        }
        location \image {
             expires 1d;
        }

Nginx日志相关优化与安全

配置日志切割

编写脚本实现nginx日志轮询
    vim cut_nginx_log.sh
    #!/bin/bash
    cd /application/nginx/log
    /bin/mv www_access.log www_access_$(date +%F -d -1day).log 
    /application/nginx/sbin/nginx -s reload 
将脚本加入定时任务定期执行
    crontab -e 
    00 00 * * * /bin/sb /root/cut_nginx_log.sh > /dev/null 2 >&1

不需要记录的日志

比如访问一些图片等是不需要记录日志的
    location ~ .*\. (js|jpg}JPG|jpeg|css|bmp|gif|GIF|)$ {
        access_log off;
    }
说明:用location标签匹配不记录日志的元素扩展名,然后关掉日志

Nginx站点目录及文件URL访问控制

根据扩展名限制程序和文件访问

location ~ ^/images/.*\.(php|php5|.sh|.pl|.py)$ {
    deny all;
}
location ~ ^/static/.*\.(php|pph5|.sh|.pl|.py)$ {
    deny all;
}    
说明:用location标签匹配不被解析的文件,然后关掉访问权限    

禁止访问指定目录下所有的文件和目录

单目录
location ~ ^/(static)/ {        #写法一
    deny all;
}
location ~ ^/static {           #写法二
    deny all'
}
    
多目录
location ~ ^/(static|image) {
    deny all;
}

禁止访问指定目录,如果访问就返回404

location /admin/ {
    return 404;
}
location /templates/ {
    return 403; 
}

限制来源IP访问

应用场景:网站后台,只允许个别IP或者网段访问
location ~ ^/oldboy/{
    allow 192.168.0.20;
    deny all;
}
        
location ~ ^/admin/ {
    deny 192.168.0.1;
    allow 192.168.0.0/24;
    allow 10.1.1.0/16;
    deny all;          #一旦deny all;下面就不能再接IP或者IP段了
}

Nginx防止恶意解析

什么是恶意解析

假如你们公司里web服务器是多台组成的一个集群,所以IP是不一样的,对方在ping你们域名的时候会出来一个IP,但是这个IP不是万网对应你们域名的IP,然后他们拿到这个IP,在万网上边把他们的域名解析到你这个IP上来,这就造成一个问题:如果他们的域名没备案的话,公安局就会一直找你们公司

解决方案

让使用IP直接访问网站的,或者访问恶意解析到你们公司IP的域名,收到501错误

配置

server {                       #这个虚拟主机必须放在其他虚拟主机的前边
    listen 80 default_server;
    server_name _;
    return 501;
}
说明:假如nginx多个虚拟主机,如果直接访问IP的话,nginx会默认访问第一个虚拟主机,所以通过IP直接访问的话就是访问第一个虚拟主机,就会报501错误,如果其他域名恶意解析到你这个IP上了也会返回501错误

Nginx配置防盗链

什么是资源盗链

假如把别人网站上的一段视频或一张图片,复制链接,然后放在自己的网站上,用户来自己网站访问这些内容的时候,承受负担和流量的是别人的服务器

常见防盗链解决方案基本原理

根据http referer实现防盗链

在HTTP协议中,有一个表头字段叫referer,使用URL格式来表示从哪里来的链接到当前网页的资源.
通过referer可以检测目标访问的来源网页,如果是资源文件,可以跟踪到显示它的网页地址,一旦检测出来不是本站,马上执行阻止或者返回指定图片、错误信息等
一句话说明:只允许指定的域名使用资源文件,如果其他域名使用则返回指定错误信息

什么是HTTP referer  

HTTP referer是header的一部分,当浏览器向Web服务器发送请求的时候,一般会带上referer,告诉我服务器我是从哪个页面链接过来的.

配置通过referer实现防盗链 

编辑nginx.conf配置文件,加入第三个location字段部分,可以根据实际情况修改
    vim nginx.conf
    server {
    listen       80;
    server_name  blog.etiantian.org;
    root  html/blog;
    location / {
        index  index.php index.html index.htm;
    }
    location ~ .*\.(php|php5)?$ {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        include fastcgi.conf;
     }
             
     location ~* \.(jpg|gif|png|swf|flv|wma|asf|mp3|mmf|zip|rar)$ {
        valid_referers none  blocked *.etiantian.org etiantian.org      #允许使用资源文件的域名
        if ($invalid_referer){                                          #如果不是上边允许的域名使用资源文件的时候,就返回另一张图片,或者返回403也可以
            rewrite ^/http://blog.etiantian.org/img/nolink.jps
        }
    #通过location匹配需要防盗的资源文件    
     }
             access_log logs/access_blog.log main;
}

Nginx错误页面优雅显示

参数:error_page

可放位置:http,server

原理:如果发现404错误等,也可以是其他错误代码,自动跳转到某个页面(页面自定义)

配置404优雅显示 

编辑nginx.conf配置文件,放在server下面就是针对某个虚拟主机的404做优雅显示,放在http就是对所有虚拟主机的404做优雅显示
vim nginx.conf
    server {
    listen       80;
    server_name  blog.etiantian.org;
    root  html/blog;
    location / {
        index  index.php index.html index.htm;
    }
    location ~ .*\.(php|php5)?$ {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        include fastcgi.conf;
     }
     #方法一
     error_page 404 /error/404.html           #如果发现404错误就跳转到html/blog/error/404.html页面
     #方法二
     error_page 404 www.baidu.com             #如果发现404错误就跳转到www.baidu.com
     方法三 
     error_page  404 403     /error/404.html  #如果发现404、403错误就跳转指定页面
     access_log logs/access_blog.log main;
}

Nginx站点目录文件及目录权限优化

单机LNMP环境,站点目录和文件属性设置如下

所有目录权限755 所有文件权限644 所有目录和文件属主属组都是root 用户上传资源的目录权限755,属主属组都是nginx服务用户

集群参考

Nginx限制HTTP请求

我们可以通过nginx限制http请求的方法来达到提升服务器安全的目的,例如:让http只能使用GET、HEAD、POST放的配置如下

if (request_method !~ ^T|HEAD|POST)$) {
    return 501;
}      

还可以通过限制上传服务器的Web服务(可以具体到文件)使用GET方法,来达到防止用户通过上传服务器访问存储内容,让访问存储渠道只能从静态或图片服务器入口进入,例如在上传上限制HTTP的GET方法

if ($request_method ~* ^(GET)$) {
    return 501;
}
#请参考专业的nginx架构逻辑图

基于nginx Web服务linux系统内核参数优化

http://oldboy.blog.51cto.com/2561410/1336488
http://yangrong.blog.51cto.com/6945369/1321594

Nginx程序架构优化

为网站程序解耦 

简单的说就是把一堆程序代码按照业务员用途分开,然后提供方服务,例如:注册登录、上传、下载、浏览列表、商品内容页面、订单支付等都应该是独立的程序服务,只不过在客户端看来是一个整体
中小公司必须做到以下几个程序模块独立

  • 网页页面服务
  • 图片附件及下载服务
  • 上传图片服务

使用普通用户启动Nginx

为什么让Nginx服务使用普通用户 

默认情况下,Nignx的master进程使用的是root用户,worker进程使用的是nginx指定的普通用户,使用root用户跑nginx进程有两个最大的问题

  • 管理权限必须是root,
  • 使用root跑nginx服务,一旦网站出现漏洞,用户就可以很容易的获得服务器的root权限

给nginx服务降权解决方案 

  1. 给nginx服务降权,用inca用户跑nginx服务,给开发及运维设置普通账号,只要和inca同组即可管理nginx,该方案解决了nginx管理问题,防止root分配权限过大
  2. 开发人员使用普通账号即可管理nginx服务及其站点下的程序,看日志

给nginx服务降权实战 

安装nginx使用root用户装到/application/nginx下 

创建用来跑nginx的普通用户 

[root@lnmp02 ~]# useradd inca

配置inca用户的nginx

[root@lnmp02 ~]# su - inca 
[inca@lnmp02 ~]$ mkdir conf  www logs
[inca@lnmp02 ~]$ touch conf/nginx.conf
[inca@lnmp02 ~]$ vim nginx.conf
    worker_processes  1;
    error_log /home/inca/logs/error.log;
    user inca inca;
    pid /home/inca/logs/nginx.pid;


    events {
        worker_connections  1024;
        use epoll;
    }


    http {
        include       mime.types;
        default_type  application/octet-stream;
        sendfile   on;
        keepalive_timeout 65;

        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                          '$status $body_bytes_sent "$http_referer" '
                          '"$http_user_agent" "$http_x_forwarded_for"';

        server {
            listen       8080;
            server_name  www.etiantian.org;
            root /home/inca/www;
            location / {
                index  index.html index.htm;
            }

        access_log  /home/inca/logs/www_access.log  main;
        }

    }
[inca@lnmp02 ~]$ cp /application/nginx/conf/mime.types /home/inca/conf/.

启动Nginx

[inca@lnmp02 ~]$ /application/nginx/sbin/nginx  -c /home/inca/conf/nginx.conf 

测试Nginx进程是否是inca用户

[inca@lnmp02 ~]$ ps -ef |grep nginx
 inca      28697      1  0 02:50 ?        00:00:00 nginx: master process /application/nginx/sbin/nginx -c /home/inca/conf/nginx.conf  #可以看到nginx进程已经是inca账户了
 inca      28698  28697  0 02:50 ?        00:00:00 nginx: worker process    

Nginx页面缓存

模块:proxy_cache
缓存静态的文件,例如:CSS、JS、图片等
无缓存时用户访问流程

有缓存时用户访问流程

应用场景:Nginx作为反向代理的时候做Web页面缓存
作用

Web缓存位于Web服务器和客户端之间,当用户访问一个URL时,Web缓存服务器会去后端服务器取回要输出的内容,当下一个请求到来时,如果访问的是相同的URL,Web缓存服务器直接输出内容给客户端,就不再次向后端服务器发出请求了,从而降低了Web服务器、数据库的负载,减少了网络延迟,提高了用户访问速度

proxy_cache相关指令集

proxy_cache_path
  可放位置:http段
  语法:proxy_cache_path path [levels=number] keys_zone=zone_name:zone_size[inactive=time] [max_size=size];
  实例:proxy_cache_path /tmp/ngx_cache levels=1:2 keys_zone=cache_one:500m inactive=1d max_size=5g;
  path:存放目录
  levels:指定该缓存空间有两层目录hash目录,第一层目录为一个字母,第二层目录为两个字母,例如:/tmp/ngx_cache/c/29/xxxxxxxxxxxx
  keys_zone:指定该缓存区的名字
  500m:指内存缓存空间大小为500m
  inactive:指定过期时间,如果缓存数据在1天内没有被访问就删除
  max_size:的5g是指硬盘缓存空间为30G
  作用:用于设置缓存文件的存放路径
proxy_cache_methods
  可放位置:
  语法:proxy_cache_methods[GET HEAD POST];
  实例:proxy_cache_methods[GET HEAD];
  作用:用于设置缓存哪些HTTP方法,默认缓存HTTP的GET/HEAD方法,不缓存POST方法
proxy_cache_min_uses
  可放位置
  语法:proxy_cache_min_uses the_number
  实例:语法:proxy_cache_min_uses 1
  作用:用于设置缓存最小使用次数,默认值为1
proxy_cache_valid
  可放位置:location
  语法:proxy_cache_valid reply_code [reply_code...] time ;
  实例:proxy_cache_valid 200 304 12h;
  实例:proxy_cache_valid 301 302 1m;
  实例:proxy_cache_valid any 1m;
  作用:设置200、304状态的URL缓存12h,301、302状态的URL缓存1m,其他的都缓存1m
proxy_cache_key
  可放位置:location
  语法:proxy_cache_key line ;
  实例:proxy_cache_key $host$uri$is_args$args;
  作用:用来设置Web缓存的key值,Nginx根据Key值md5哈希存储缓存,一般根据$host(域名),$request_uri(请求的路径)等变量组合成proxy_cache_key
proxy_cache
  可放位置:location
  语法:proxy_cache [name]
  实例:proxy_cache cache_one
  作用:调用http段定义的proxy_cache_path
proxy_set_header
  可放位置:location
  实例:roxy_set_header HOST $host;
  实例:proxy_set_header X-Forwarded-For $remote_addr;
  作用:记录host主机名和客户端IP地址

配置Nginx Web缓存

环境说明

  nginx-proxy 192.168.0.93 nginx
  realserver 192.168.0.94 nginx

配置realserver

安装Nginx省略
配置nginx虚拟主机
    [root@realserver   ~]# vim /application/nginx/conf/nginx.conf
    worker_processes  1;

    events {
    worker_connections  1024;
    }


    http {
        include       mime.types;
        default_type  application/octet-stream;
        sendfile        on;
        keepalive_timeout  65;
                    


        server {
            listen       8080;

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

    }
配置网站程序
    [root@realserver   ~]# vim /application/nginx/html/test/index.html
    <img src="/root/test.jpg" />     
启动nginx
    [root@realserver   ~]# /application/nginx/sbin/nginx
测试此虚拟主机
    [root@realserver   ~]# curl 192.168.0.94:8080/index.html   #出来一张图片则为成功

配置Nginx Web缓存

安装Nginx省略
配置Nginx Web缓存
    [root@nginx-proxy ~]# vim /application/nginx/conf/nginx.conf
    worker_processes  1;

    events {
        worker_connections  1024;
    }


    http {
        include       mime.types;
        default_type  application/octet-stream;

        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                     '$status $body_bytes_sent "$http_referer" '
                     '"$http_user_agent" "$http_x_forwarded_for"';
                     '"addr:$upstream_addr-status:$upstream_status- cachestatus:$upstream_cache_status"' ;
        sendfile        on;
        keepalive_timeout  65;
        proxy_cache_path /tmp/ngx_cache levels=1:2 keys_zone=cache:500m  inactive=1d max_size=5g;
        upstream server_pool{
           server 192.168.0.194:8080;
        }


        server {
            listen       80;
            server_name  www.etiantian.org;

            location / {
               proxy_pass http://server_pool;
               proxy_cache cache;
               proxy_cache_valid 200 304 12h;
               proxy_cache_valid 301 302 1m;
               proxy_cache_valid any 1m;
               proxy_cache_key $host$uri$is_args$args;
               proxy_set_header HOST $host;
               proxy_set_header X-Forwarded-For $remote_addr;
               expires 1d;
               add_header  Nginx-Cache "$upstream_cache_status";  #curl -I的时候可以查看是否命中
            }
         access_log logs/www_access.log main;
            }
    }
     
测试Nginx Web缓存
    [root@nginx-proxy ~]# curl -I 192.168.0.93
    HTTP/1.1 200 OK
    Server: nginx/1.6.3
    Date: Sun, 06 Nov 2016 00:25:20 GMT
    Content-Type: text/html
    Content-Length: 29
    Connection: keep-alive
    Last-Modified: Sat, 05 Nov 2016 23:37:38 GMT
    ETag: "581e6d42-1d"
    Expires: Mon, 07 Nov 2016 00:25:20 GMT
    Cache-Control: max-age=86400 
    Nginx-Cache: MISS                            #可以看到第一次是MISS的,因为第一次请求Nginx还没缓存
    Accept-Ranges: bytes
            
    [root@nginx-proxy ~]# curl -I 192.168.0.93
    HTTP/1.1 200 OK
    Server: nginx/1.6.3
    Date: Sun, 06 Nov 2016 00:25:23 GMT
    Content-Type: text/html
    Content-Length: 29
    Connection: keep-alive
    Last-Modified: Sat, 05 Nov 2016 23:37:38 GMT
    ETag: "581e6d42-1d"
    Expires: Mon, 07 Nov 2016 00:25:23 GMT
    Cache-Control: max-age=86400
    Nginx-Cache: HIT                             #可以看到第二次就命中了
    Accept-Ranges: bytes 

 

posted @ 2016-11-06 02:04  差点点温柔  阅读(5151)  评论(0编辑  收藏  举报