3

软件介绍

与 Apache软件类似, Nginx ( “engme x")是一个开源的,支持高性能、高并发的 WWW服务器和代理服务软件。它是由俄罗斯人 Igor Sysoev开发的,最初被应用在勘罗斯的大型网站 www.rambler.ru 上,后来作者将源代码以类BSD许可证的形式开源出来供全球使用。

Nginx因具有高并发(特别是静态资源)占用系统资源少等特性,且功能丰富而逐渐流行起来。

在功能应用发面,Nginx不但是一个优秀的Web服务软件,还具有反向代理负载均衡功能和缓存服务功能。在反向代理负载均衡功能方面,它类似于大名鼎鼎的LVS负载均衡及Haproxy等专业代理软件,但是Nginx部署起来更为简单、方便;在缓存服务功能方面,它又类似于Squid等专业的缓存服务软件。
Nginx 的官方介绍见 http://nginx.org/en

nginx软件特性

HTTP服务器的特色及优点:

  • 支持高并发:能支持几万并发连接(特别是静态小文件业务环境)
  • 资源消耗少:在3万并发连接下,开启10个Nginx线程消耗的内存不到200MB
  • 可以做HTTP反向代理及加速缓存、即负载均衡功能,内置对RS节点服务器健康检查功能这相当于专业的Haproxy软件或LVS的功能。
  • 具备Squid等专业缓存软件等的缓存功能。
  • 支持异步网络I/O事件横型epoll(Linux2.6+)

nginx的安装

nginx的安装可参考上一篇博文,这里不再啰嗦了。介绍几个nginx管理的命令吧。
启动

 $ /usr/local/nginx/sbin/nginx 

重新加载

 $ /usr/local/nginx/sbin/nginx -s reload

检查语法

$  /usr/local/nginx/sbin/nginx -t 

杀死进程

 $ pkill nginx
 或者 
 $ killall nginx
 # 如果现实没有killall命令,执行:yum install -y psmisc

nginx配置文件详解

nginx.conf配置文件全局结构大致如下:

  • 全局配置(user,worker_process,error_log,pid)
  • events(网络连接部分,worker_connections)
  • http(最重要的部分,大部分功能都在这里)
  • server(虚拟主机相关,在http块里)
  • location(server里面)

全局配置部分

user nobody;
# 定义运行nginx服务的用户,还可以加上组,如 user nobody nobody;
worker_processes 1;
# 定义nginx子进程数量,即提供服务的进程数量,该数值建议和服务cpu核数保持一致。
# 除了可以定义数字外,还可以定义为auto,表示让系统自动调整。
error_log logs/error.log;
# 定义错误日志的路径,可以是相对路径(相对prefix路径的),也可以是绝对路径。
# 该配置可以在此处定义,也可以定义到http、server、location里。
error_log logs/error.log notice;
# 定义错误日志路径以及日志级别.
# 错误日志级别:常见的错误日志级别有[debug|info|notice|warn|error|crit|alert|emerg],级别越高记录的信息越少。
# 如果不定义默认是error
pid logs/nginx.pid;
# 定义nginx进程pid文件所在路径,可以是相对路径,也可以是绝对路径。
worker_rlimit_nofile 100000;
# 定义nginx最多打开文件数限制。如果没设置的话,这个值为操作系统(ulimit -n)的限制保持一致。
# 把这个值设高,nginx就不会有“too many open files”问题了。

events配置部分

worker_connections 1024;

定义每个work_process同时开启的最大连接数,即允许最多只能有这么多连接。


accept_mutex on;

当某一个时刻只有一个网络连接请求服务器时,服务器上有多个睡眠的进程会被同时叫醒,这样会损耗一定的服务器性能。Nginx中的accept_mutex设置为on,将会对多个Nginx进程(worker processer)接收连接时进行序列化,防止多个进程争抢资源。 默认就是on。


multi_accept on;

nginx worker processer可以做到同时接收多个新到达的网络连接,前提是把该参数设置为on。
默认为off,即每个worker process一次只能接收一个新到达的网络连接。


use epoll;

Nginx服务器提供了多个事件驱动器模型来处理网络消息。
其支持的类型有:select、poll、kqueue、epoll、rtsing、/dev/poll以及eventport

  • select:只能在Windows下使用,这个事件模型不建议在高负载的系统使用
  • poll:Nginx默认首选,但不是在所有系统下都可用
  • kqueue:这种方式在FreeBSD 4.1+, OpenBSD2.9+, NetBSD 2.0, 和 MacOS X系统中是最高效的
  • epoll: 这种方式是在Linux 2.6+内核中最高效的方式
  • rtsig:实时信号,可用在Linux 2.2.19的内核中,但不适用在高流量的系统中
  • /dev/poll: Solaris 7 11/99+,HP/UX 11.22+, IRIX 6.5.15+, and Tru64
    UNIX 5.1A+操作系统最高效的方式
  • eventport: Solaris 10最高效的方式

http配置部分

常见配置:

include       mime.types;  //cat conf/mime.types

定义nginx能识别的网络资源媒体类型(如,文本、html、js、css、流媒体等)

default_type  application/octet-stream;

定义默认的type,如果不定义改行,默认为text/plain.

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

定义nginx日志格式,其中main为日志格式的名字,后面的为nginx的内部变量组成的一串字符串。

access_log logs/access.log main; 

定义日志的路径以及采用的日志格式,该参数可以在server配置块中定义。

sendfile on;

是否调用sendfile函数传输文件,默认为off,使用sendfile函数传输,可以减少user mode和kernel mode的切换,从而提升服务器性能。对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。

sendfile_max_chunk 128k;

该参数限定Nginx worker process每次调用sendfile()函数传输数据的最大值,默认值为0,如果设置为0则无限制。

tcp_nopush on;

当tcp_nopush设置为on时,会调用tcp_cork方法进行数据传输。
使用该方法会产生这样的效果:当应用程序产生数据时,内核不会立马封装包,而是当数据量积累到一定量时才会封装,然后传输。这样有助于解决网络堵塞问题。默认值为on。举例:快递员收快递、发快递,包裹累积到一定量才会发,节省运输成本。

keepalive_timeout 65 60;

该参数有两个值,第一个值设置nginx服务器与客户端会话结束后仍旧保持连接的最长时间,单位是秒,默认为75s。
第二个值可以省略,它是针对客户端的浏览器来设置的,可以通过curl -I看到header信息中有一项Keep-Alive: timeout=60,如果不设置就没有这一项。
第二个数值设置后,浏览器就会根据这个数值决定何时主动关闭连接,Nginx服务器就不操心了。但有的浏览器并不认可该参数。

send_timeout

这个超时时间是发送响应的超时时间,即Nginx服务器向客户端发送了数据包,但客户端一直没有去接收这个数据包。
如果某个连接超过send_timeout定义的超时时间,那么Nginx将会关闭这个连接。

client_max_body_size 10m;

浏览器在发送含有较大HTTP包体的请求时,其头部会有一个Content-Length字段,client_max_body_size是用来限制Content-Length所示值的大小的。
这个限制包体的配置不用等Nginx接收完所有的HTTP包体,就可以告诉用户请求过大不被接受。会返回413状态码。
例如,用户试图上传一个1GB的文件,Nginx在收完包头后,发现Content-Length超过client_max_body_size定义的值,
就直接发送413(Request Entity Too Large)响应给客户端。

gzip on;

是否开启gzip压缩。

gzip_min_length 1k;

设置允许压缩的页面最小字节数,页面字节数从header头得content-length中进行获取。默认值是20。建议设置成大于1k的字节数,小于1k可能会越压越大。

gzip_buffers 4 16k;

设置系统获取几个单位的buffer用于存储gzip的压缩结果数据流。4 16k代表分配4个16k的buffer。

gzip_http_version 1.1;

用于识别 http 协议的版本,早期的浏览器不支持 Gzip 压缩,用户会看到乱码,所以为了支持前期版本加上了这个选项。
如果你用了Nginx反向代理并期望也启用Gzip压缩的话,由于末端通信是http/1.1,故请设置为 1.1。

gzip_comp_level 6;

gzip压缩比,1压缩比最小处理速度最快,9压缩比最大但处理速度最慢(传输快但比较消耗cpu)

gzip_types mime-type ... ;

匹配mime类型进行压缩,无论是否指定,”text/html”类型总是会被压缩的。在conf/mime.conf里查看对应的type。
示例:gzip_types text/plain application/x-javascript text/css text/html application/xml;

gzip_vary on;

和http头有关系,会在响应头加个 Vary: Accept-Encoding ,可以让前端的缓存服务器缓存经过gzip压缩的页面,例如,用Squid缓存经过Nginx压缩的数据。

gzip_proxied any;

Nginx作为反向代理的时候启用,决定开启或者关闭后端服务器返回的结果是否压缩,匹配的前提是后端服务器必须要返回包含”Via”的 header头。
以下为可用的值:

  • 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 - 无条件启用压缩

nginx服务优化

虚拟主机

1、虚拟主机概念

虚拟主机指的是,在web服务里是一个独立的网站站点,这个站点对应独立的域名,也可能是IP或端口,具有独立的程序及资源目录,可以独立地对外提供服务供用户访问。Nginx软件是使用一个server{}标签来标识一个虚拟主机的。一个web服务里可以有多个虚拟主机标签对,即可同时支持多个虚拟主机站点。

2、虚拟主机类型

常见的虚拟主机类型分三种

  1. 基于域名的虚拟主机
  2. 基于端口的虚拟主机
  3. 基于IP的虚拟主机

基于域名的虚拟主机是通过不同域名区分不同的虚拟主机,是企业应用最广泛的虚拟主机类型。
基于端口的虚拟主机是通过不同端口区分不同的虚拟主机,常用于公司内部的网站,比如不希望用户访问的网站后台等。
基于IP地址的虚拟主机是通过不同IP地址区分不同的虚拟主机,不常用很少见。

3、基于域名的虚拟主机配置
第一、编辑nginx配置文件nginx.conf,找到http{}块,在http{}块里面添加server{}标签,一个server{}代表一个虚拟主机。默认nginx.conf中有一个server{},这里修改一下,并配置两个基于域名的虚拟主机。
配置内容如下:

server {
        listen 80;
        server_name www.syushin.com;
        location / {
                root    html/com;
                index   index.html index.htm;
                }               
        }
server {
        listen 80;
        server_name www.syushin.org;
        location / {
                root    html/org;
                index   index.html index.htm;
                }               
        }        

可以看到基于域名的虚拟是在server_name中定义。

第二、创建域名对应的站点目录及文件。

$ mkdir ../html/com ../html/org
$ echo "I am syushin.com" >> ../html/com/index.html
$ echo "I am syushin.org" >> ../html/org/index.html

第三、配置域名解析
linux下
echo "192.168.30.7 www.syushin.com www.syushin.org" >> /etc/hosts

windows下
找到域名解析文件,通常在C:\Windows\System32\drivers\etc\hosts
添加内容:192.168.30.7 www.syushin.com www.syushin.org

第四、检查nginx语法,重新加载

$ /usr/local/nginx/sbin/nginx -t
$ /usr/local/nginx/sbin/nginx -s reload

第五、测试
linux下用curl命令测试

[root@lnmp conf]$ curl www.syushin.com
I am syushin.com
[root@lnmp conf]$ curl www.syushin.org
I am syushin.org

windows下用浏览器访问

clipboard.png

clipboard.png

这样就可以实现基于域名的虚拟主机了,用户输入不同的域名,访问不同的站点内容。而基于端口的虚拟主机是在server{}标签里的listen处修改监听的端口,比如listen 8080;或者listen 8090;
基于IP地址也是在listen里修改,格式如下:192.168.30.7:80;或者192.168.30.8:81
都很简单,就不再实际操作了。

规范优化nginx配置文件

nginx主配置文件是nginx.conf,可以将主配置文件包含所有虚拟主机的子配置文件统一放入extra目录里。
使用include参数实现,它可以放在nginx配置文件的任何地方,用法示例如下:

$ include extra/web01.conf

下面是我的使用方案:
$ vim nginx.conf在http{}删除默认的server{}标签,使用include extra/*.conf;

http
{
    include mime.types;
    default_type application/octet-stream;
    ...(这里省略)
    include extra/*.conf; #就是这一行
}

创建虚拟主机配置保存的目录

$ mkdir /usr/local/nginx/conf/extra

进入extra目录,创建虚拟主机配置文件。

$ vim web01.conf
# 内容如下
server {
        listen 80;
        server_name localhost;
        index index.html index.htm ;
        root html;
    }

这样通过主配置文件加上include包含的配置使得Nginx配置更加简单,清晰,规范。

域名重定向

在一个虚拟主机上有多个域名的时候,可以针对这多个域名做域名重定向。即访问A域名,浏览器会跳转到B域名。

server {
        listen 80;
        server_name www.syushin.com blog.syushin.cc;
        if ($host = 'blog.syushin.cc' ) {
                rewrite  /(.*)  http://syushin.com/$1  permanent;
        }
        index index.html index.htm index.php;
        root html/web01;
}

虚拟主机配置如上:其中if语句就是域名重定向的配置了。$host变量就是域名,当访问域名是blog.syushin.cc的时候,就将域名跳转到www.syushin.com。
测试:

[root@lnmp ~]$ curl -x127.0.0.1:80 www.syushin.com -I
HTTP/1.1 200 OK # 正常访问状态码200
Server: nginx/1.14.2
Date: Sun, 10 Mar 2019 13:00:16 GMT
Content-Type: text/html
Content-Length: 12
Last-Modified: Sun, 10 Mar 2019 12:38:09 GMT
Connection: keep-alive
ETag: "5c850531-c"
Accept-Ranges: bytes

[root@lnmp ~]$ curl -x127.0.0.1:80 blog.syushin.cc -I 
HTTP/1.1 301 Moved Permanently # 状态码301
Server: nginx/1.14.2
Date: Sun, 10 Mar 2019 13:00:25 GMT
Content-Type: text/html
Content-Length: 185
Connection: keep-alive
Location: http://www.syushin.com/ # 重定向域名

用户认证

nginx访问日志

nginx访问日志就是用户访问网站的记录。可以针对不同格式记录日志。
配置nginx访问日志格式(这里只使用其中一部分):

   
  # 在nginx主配置文件中的http{}块里定义
 log_format main '$remote_addr $http_x_forwarded_for [$time_local]'
    ' $host "$request_uri" $status'
    ' "$http_referer" "$http_user_agent"';

参数说明:

变量 描述
$remote_addr 客户端IP(公网IP)
$http_x_forwarded_for 代理服务器的IP
$time_local 服务器本地时间
$host 访问主机名(域名)
$request_url 访问的url地址
$status 状态码
$http_referer referer
$http_user_agent user_agent

虚拟主机配置文件爬配置nginx访问日志保存目录以及使用主配置文件里的日志格式:

server {
        listen 80;
        server_name www.syushin.com blog.syushin.cc;
        if ($host = 'blog.syushin.cc' ) {
                rewrite  /(.*)  http://www.syushin.com/$1  permanent;
        }
        index index.html index.htm index.php;
        root html/web01;
        location ~ \.php$
        {
            include fastcgi_params;
            fastcgi_pass unix:/tmp/php-fcgi.sock;
            fastcgi_index index.php;
            fastcgi_param SCRIPT_FILENAME /usr/local/nginx/html$fastcgi_script_name;
        }
        access_log /var/log/nginx/syushin_access.log main; # 这一行就是配置访问日志

}

创建日志文件目录

$ mkdir -p /var/log/nginx

检查语法、重新加载

[root@lnmp conf]$ $ /usr/local/nginx/sbin/nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@lnmp conf]$ /usr/local/nginx/sbin/nginx -s reload

测试,浏览器访问一次域名和在本地curl一下,查看是否有日志生成。

[root@lnmp nginx]$ curl -x127.0.0.1:80 blog.syushin.cc 
<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx/1.14.2</center>
</body>
</html>
[root@lnmp nginx]$ cat syushin_access.log 
192.168.30.1 - [11/Mar/2019:12:55:01 +0800] www.syushin.com "/" 304 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"
127.0.0.1 - [11/Mar/2019:12:56:32 +0800] blog.syushin.cc "/" 301 "-" "curl/7.29.0"

这样配置访问日志就成功了。

日志切割

生产环境下,访问日志的量是很大的,如果把访问日志都放在一个文件里是会有很大影响的。因此将nginx访问日志进行切割是很有必要的。
如何切割日志?Linux有个日志切割工具logrotate。它的配置文件在/etc/logrotate.conf
查看配置文件

# see "man logrotate" for details
# rotate log files weekly
weekly

# keep 4 weeks worth of backlogs
rotate 4

# create new (empty) log files after rotating old ones
create

# use date as a suffix of the rotated file
dateext

# uncomment this if you want your log files compressed
#compress

# RPM packages drop log rotation information into this directory
include /etc/logrotate.d

# no packages own wtmp and btmp -- we'll rotate them here
/var/log/wtmp {
    monthly
    create 0664 root utmp
        minsize 1M
    rotate 1
}

/var/log/btmp {
    missingok
    monthly
    create 0600 root utmp
    rotate 1
}

其中weekly表示按周切割;
rotate 4表示一次存储4个归档文件,对于第5个归档文件,时间最久的文档会被覆盖;
create以指定的权限创建全新的日志文件,同时logrotate也会重命名原始日志文件。
dataext表示以日期为格式命令新的日志文件

/var/log/wtmp {
        monthly
        create 0664 root utmp
            minsize 1M
        rotate 1
    }

上面代码块表示针对/var/log/wtmp这个目录下做日志切割,时间为一个月,只对文件大小大于1M文件进行切割。

对于nginx的日志切割
如果是yum安装的nginx,logrotate已经有默认的切割策略了/etc/logrotate.d/nginx
而编译安装的nginx就没有,需要手动定义,也可以用这个日志配置

$ cat /etc/logrotate.d/nginx 
/var/log/nginx/*.log {
    daily
    rotate 5
    missingok
    notifempty
    create 644 www www
    postrotate
      if [ -f /application/nginx/logs/nginx.pid ]; then
          kill -USR1 `cat /application/nginx/logs/nginx.pid`
      fi
endscript
}

logrotate工具对于防止因庞大的日志文件而耗尽存储空间是十分有用的。配置完毕后,进程是全自动的,可以长时间在不需要人为干预下运行。除了样例之外,自己还可以定制不同的样式满足需求。

访问日志不记录静态文件

在访问日志里,过滤掉一些图片、js、css等的请求日志。因为这样的日志没有多大意义,而且会占用很大的磁盘空间。
配置,编辑虚拟主机配置文件,添加location:

location ~* \.(png|jpeg|jpg|gif|js|css|bmp)$
        {
                access_log off;
        }

上面规则表示凡是匹配到以.png|jpeg|jpg|gif|js|css|bmp结尾的文件,访问日志功能就关闭,即不记录访问静态文件的访问记录。*号表示不区分大小写,.号前面需要只用转义字符,|表示或者。
测试
在虚拟主机站点目录里添加资源文件test.png,然后curl访问一下、再查看日志是否有记录这条访问记录,如果没有则表示配置成功。
清空日志

$ > /var/log/nginx/syushin_access.log 

创建以png结尾的文件

$ touch /usr/local/nginx/html/web01/test.png    

访问

# 成功访问
[root@lnmp web01]$ curl -x127.0.0.1:80 www.syushin.com/test.png -I
HTTP/1.1 200 OK
Server: nginx/1.14.2
Date: Mon, 11 Mar 2019 05:19:58 GMT
Content-Type: image/png
Content-Length: 0
Last-Modified: Mon, 11 Mar 2019 05:16:14 GMT
Connection: keep-alive
ETag: "5c85ef1e-0"
Accept-Ranges: bytes

查看日志

[root@lnmp web01]# cat /var/log/nginx/syushin_access.log 
[root@lnmp web01]# 

无日志记录,说明配置成功。

防盗链

盗链是指服务提供商自己不提供服务的内容,通过技术手段绕过其它有利益的最终用户界面(如广告),直接在自己的网站上向最终用户提供其它服务提供商的服务内容,骗取最终用户的浏览和点击率。受益者不提供资源或提供很少的资源,而真正的服务提供商却得不到任何的收益。

防盗链就是防止上面情况的。常见的盗链是图片盗链,音频盗链,文件盗链。

Referer 防盗链
Referer在HTTP协议里有特殊的用途,当浏览器向服务器发送请求时,一般会带上
Referer头,告知服务器该请求是从哪个页面链接过来的。Referer经常被用于页面访问统计、图片防盗链等。

配置图片防盗链

location ~ \.(png|gif|jpeg|bmp|mp3|mp4|flv)$
        {
                valid_referers none blocked server_name *.syushin.com;
                if ($invalid_referer){
                    return 403;
                }
        }

valid referers指的是白名单内的域名可以引用站点图片
none表示空referer,即直接打开站点的图片,而不是从其他网站打开本站点的图片文件,因此对直接访问站点内容的不做限制。
blocked指的是非法链接
server_name就是虚拟主机域名
后面的*.syushin.com就是白名单域名
这样配置后,当从其他网站引用本站的图片的时候,就引用不了了。
测试:使用curl -e选项测试,-e指定referer

$ curl -I -e "http://www.aaa.com/1.txt" http://www.syushin.com/test.png

出现403说明配置成功


syushin
948 声望316 粉丝