Loading... # [Nginx高性能web服务器](https://pan.baidu.com/s/13qURHj6mCydNd44fzN9beA?pwd=21t0) # [Nginx高性能web服务器详细讲解](https://baijiahao.baidu.com/s?id=1668820729534258806) ## 介绍 ### 入门 #### Nginx概述 **Nginx服务器是一款免费开源的高性能、轻量级HTTP服务器及反向代理服务器产品,能够提供IMAP/POP3代理服务** 等功能。是 [lgor Sysoev](https://www.dongchedi.com/article/6844826261479490059) 为俄罗斯访问量居首的 [Rambler.ru](https://www.rambler.ru/) 站点(www.rambler.ru)设计开发的。 Nginx功能丰富, **可作为HTTP服务器,也可作为反向代理服务器,邮件服务器** 。能够快速响应静态页面的请求,支持 **FastCGI、SSL、Virtual Host、URL Rewrite、Gzi** p等大量使用功能,并且支持很多第三方的模块扩展 #### 主要功能 反向代理 负载均衡 HTTP服务器(包含动静分离) 正向代理 #### 可以参考的书目 ##### https://www.w3cschool.cn/nginx/ ##### http://tengine.taobao.org/ ##### https://nginx.cn/ ### 特性 #### 简单描述 Nginx使用基于事件驱动架构,使得其可以支持数以百万级别的TCP连接 高度的模块化和自由软件许可证是的第三方模块层出不穷 Nginx是一款自由的、开源的、高性能的HTTP服务器和反向代理服务器; 同时也是一个IMAP、POP3、SMTP代理服务器; #### Nginx特点 1、轻量级,采用C进行编写,同样的web服务,会占用更少的内存及资源。 2、抗并发,nginx以epollandkqueue作为开发模型,处理请求是异步非阻塞的,负载能力比apache高很多,而apache则是阻塞型的。在高并发下nginx能保持低资源低消耗高性能,而apache在PHP处理慢或者前端压力很大的情况下,很容易出现进程数飙升,从而拒绝服务的现象。 3、nginx在开启时,会生成一个master进程,然后,master进程会fork多个worker子进程,最后每个用户的请求由worker的子线程处理。 4、可以配置nginx的upstream实现nginx的反向代理。 5、nginx作为负载均衡服务器,支持7层负载均衡。 6、nginx处理静态文件好,静态处理性能比apache高三倍以上。 7、支持高并发连接,每秒最多的并发连接请求理论可以达到50000个。 8、nginx配置简洁,正则配置让很多事情变得简单,而且改完配置能使用-t测试配置有没有问题,apache配置复杂,重启的时候发现配置出错了,会很崩溃。 9、用线程处理用户请求,而线程是共享内存的,只需要开启少量进程,多个线程就可以共享进程的内存,占用内存小。 10、一个进程死掉时,会影响到多个用户的使用,稳定性差。 11、nginx的设计高度模块化,编写模块相对简单。 12、nginx本身就是一个反向代理服务器,而且可以作为非常优秀的邮件代理服务器。 13、启动特别容易,并且几乎可以做到7*24不间断运行,即使运行数个月也不需要重新启动,还能够不间断服务的情况下进行软件版本的升级。 14、社区活跃,各种高性能模块出品迅速。 #### Apache特点 1、select同步阻塞。 2、一个连接对应一个进程。 3、用进程处理用户请求,用MPM(多处理模块)来绑定到网络端口上,接受请求,调度子进程处理请求。 4、当用户请求过多时,开启的进程较多,占用内存大,每秒最多的并发连接请求最多不超过3000个。 5、一个进程死掉时,不会影响其他的用户 6、apache的rewrite比nginx强大,在rewrite频繁的情况下,用apache。 7、apache发展到现在,模块超多,基本想到的都可以找到。 8、apache更为成熟,少bug,nginx的bug相对较多。 9、apache超稳定。 10、apache对PHP支持比较简单,nginx需要配合其他后端用。 11、apache在处理动态请求有优势,一般动态请求要apache去做,nginx适合静态和反向。 12、apache仍然是目前的主流,拥有丰富的特性,成熟的技术和开发社区。 #### 核心区别 两者最核心的区别在于apache是同步多进程模型,一个连接对应一个进程,而nginx是异步的,多个连接(万级别)可以对应一个进程。一般来说,需要性能的web服务,用nginx。如果不需要性能只求稳定,更考虑apache,apache的各种功能模块实现比nginx好,例如ssl的模块就比nginx好,可配置项多。 epoll(freebsd上是kqueue)网络IO模型是nginx处理性能高的根本理由,但并不是所有的情况下都是epoll大获全胜的,如果本身提供静态服务的就只有寥寥几个文件,apache的select模型或许比epoll更高性能。当然,这只是根据网络IO模型的原理作的一个假设,真正的应用还是需要实测。更为通用的方案是,前端nginx抗并发,后端apache集群,配合起来会更好。 ### 安装启动 #### Centos系统安装 [Centos系统安装](https://www.cnblogs.com/chaofanq/p/15022916.html) #### Ubuntu系统安装 ##### 1.首先查看linux系统 ```bash cat /proc/version Linux version 4.9.59-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.9.3 (crosstool-NG crosstool-ng-1.22.0-88-g8460611) ) #1047 SMP Sun Oct 29 12:19:23 GMT 2017 # 这表示Ubantu系统 ``` ##### 2.安装nginx ```bash sudo apt-get install nginx ``` 过程会让选一个Y同意占用内存。 ##### 3.如果出现无法定位nginx包,进行如下操作: ```bash sudo apt-get update ``` ##### 4.更新完成之后,安装nginx ```bash sudo apt-get install nginx ``` ##### 5.Ubuntu安装之后的文件结构大致为: 1)所有的配置文件都在/etc/nginx下,并且每个虚拟主机已经安排在了/etc/nginx/sites-available下 2)程序文件在/usr/sbin/nginx 3)日志放在了/var/log/nginx中 4)并已经在/etc/init.d/下创建了启动脚本nginx 5)默认的虚拟主机的目录设置在了/var/www/nginx-default (有的版本默认的虚拟主机的目录设置在了/var/www, 请参考/etc/nginx/sites-available里的配置) #### macbook安装 首先确保有brew软件。 ##### 安装 ```bash brew search nginx brew install nginx ``` #### 做个软连接 ```bash ln -s /usr/local/sbin/nginx /usr/bin/nginx ``` #### 常用指令 > nginx -V 查看版本,以及配置文件地址 > nginx -v 查看版本 > nginx -c filename 指定配置文件 > nginx -h 帮助 > nginx -s reload|reopen|stop|quit // 重新加载配置|重启|停止|退出 nginx")重新加载配置|重启|停止|退出 nginx > nginx -t //查看配置是否有语法错误 > nginx -c /usr/local/etc/nginx/nginx.conf //启动是加载指定nginx.conf文件 ### 基础必会 ## 常用功能 ### 反向代理 **反向代理应该是Nginx做的最多的一件事了** ,什么是反向代理呢,以下是百度百科的说法:反向代理(Reverse Proxy)方式是 **指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。** 简单来说就是 **真实的服务器不能直接被外部网络访问,所以需要一台代理服务器,而代理服务器能被外部网络访问的同时又跟真实服务器在同一个网络环境,当然也可能是同一台服务器,端口不同而已。** 下面贴上一段简单的实现反向代理的代码 ```bash server { listen 80; server_name localhost; client_max_body_size 1024M; location / { proxy_pass http://localhost:8080; proxy_set_header Host $host:$server_port; } } ``` 保存配置文件后启动Nginx,这样当我们 **访问localhost的时候,就相当于访问localhost:8080了** ### 负载均衡 负载均衡也是Nginx常用的一个功能,负载均衡其意思就是 **分摊到多个操作单元上进行执行** ,例如Web服务器、FTP服务器、企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务。简单而言就是 **当有2台或以上服务器时,根据规则随机的将请求分发到指定的服务器上处理,负载均衡配置一般都需要同时配置反向代理,通过反向代理跳转到负载均衡** 。而Nginx目前支持 **自带3种负载均衡策略** ,还有 **2种常用的第三方策略** 。 #### 1、RR(默认) **每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。** 简单配置 ```bash upstream test { server localhost:8080; server localhost:8081; } server { listen 81; server_name localhost; client_max_body_size 1024M; location / { proxy_pass http://test; proxy_set_header Host $host:$server_port; } } ``` 负载均衡的核心代码为 ```bash upstream test { server localhost:8080; server localhost:8081; } ``` 这里我配置了2台服务器,当然实际上是一台,只是端口不一样而已,而8081的服务器是不存在的,也就是说访问不到,但是我们访问http://localhost的时候,也不会有问题,会默认跳转到http://localhost:8080具体是因为Nginx会自动判断服务器的状态, **如果服务器处于不能访问(服务器挂了),就不会跳转到这台服务器,所以也避免了一台服务器挂了影响使用的情况,由于Nginx默认是RR策略,所以我们不需要其他更多的设置。** #### 2、权重 **指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。** 例如 ```bash upstream test { server localhost:8080 weight=9; server localhost:8081 weight=1; } ``` **那么10次一般只会有1次会访问到8081,而有9次会访问到8080** #### 3、ip_hash 上面的2种方式都有一个问题,那就是下一个请求来的时候请求可能分发到另外一个服务器,当我们的程序不是无状态的时候(采用了session保存数据),这时候就有一个很大的很问题了,比如把登录信息保存到了session中,那么跳转到另外一台服务器的时候就需要重新登录了,所以很多时候我们需要一个客户只访问一个服务器,那么就需要用iphash了, **iphash的每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。** ```bash upstream test { ip_hash; server localhost:8080; server localhost:8081; } ``` #### 4、fair(第三方) **按后端服务器的响应时间来分配请求,响应时间短的优先分配。** ```bash upstream backend { fair; server localhost:8080; server localhost:8081; } ``` #### 5、url_hash(第三方) **按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。** 在upstream中加入hash语句,server语句中不能写入weight等其他的参数,hash_method是使用的hash算法 ```bash upstream backend { hash $request_uri; server localhost:8080; server localhost:8081; } ``` 以上5种负载均衡各自适用不同情况下使用,所以可以根据实际情况选择使用哪种策略模式,不过 **fair和url_hash需要安装第三方模块才能使用** ,由于本文主要介绍Nginx能做的事情,所以Nginx安装第三方模块不会再本文介绍 #### 拓展 [yum安装nginx没有某一模块,该如何添加第三方模块?](https://blog.58heshihu.com/index.php/archives/932/) [Nginx几款负载均衡第三方插件的安装与使用](https://blog.58heshihu.com/index.php/archives/935/) ### 正向代理 正向代理,意思是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。 **客户端才能使用正向代理** 。当你需要把你的服务器作为代理服务器的时候,可以用Nginx来实现正向代理,但是目前Nginx有一个问题,那么就是不支持HTTPS,虽然我百度到过配置HTTPS的正向代理,但是到最后发现还是代理不了,当然可能是我配置的不对,所以也希望有知道正确方法的同志们留言说明一下。 ```bash resolver 114.114.114.114 8.8.8.8; server { resolver_timeout 5s; listen 81; access_log e:wwwrootproxy.access.log; error_log e:wwwrootproxy.error.log; location / { proxy_pass http://$host$request_uri; } } ``` resolver是配置正向代理的DNS服务器,listen 是正向代理的端口,配置好了就可以在ie上面或者其他代理插件上面使用服务器ip+端口号进行代理了。 #### 拓展 [Nginx-正向代理实现 ](https://www.cnblogs.com/yanjieli/p/15229907.html) Nginx本身也是一个静态资源的服务器,当只有静态资源的时候,就可以使用Nginx来做服务器,同时现在也很流行动静分离,就可以通过Nginx来实现,首先看看Nginx做静态资源服务器 ```bash server { listen 80; server_name localhost; client_max_body_size 1024M; location / { root e:wwwroot; index index.html; } } ``` 这样如果访问http://localhost就会默认访问到E盘wwwroot目录下面的index.html,如果一个网站只是静态页面的话,那么就可以通过这种方式来实现部署。 ### HTTP服务器(动静分离) Nginx本身也是一个静态资源的服务器,当只有静态资源的时候,就可以使用Nginx来做服务器,同时现在也很流行动静分离,就可以通过Nginx来实现,首先看看Nginx做静态资源服务器 ```bash server { listen 80; server_name localhost; client_max_body_size 1024M; location / { root e:wwwroot; index index.html; } } ``` 这样如果访问http://localhost就会默认访问到E盘wwwroot目录下面的index.html,如果一个网站只是静态页面的话,那么就可以通过这种方式来实现部署。 ## 技能点汇总 ### 显示乱码 ```bash server { listen 80; server_name example.com; root /var/www/example; location / { charset utf-8; #一般是在个别的location中加入此项,具体情况具体对待 rewrite .* /index.html break; } } ``` ### 打开目录浏览功能 Nginx默认是 **不允许列出整个目录** 的。如需此功能, **打开nginx.conf文件,在location server 或 http段中加入** ```bash autoindex on; ``` 另外两个参数最好也加上去: > autoindex\_exact\_size off; > 默认为on,显示出文件的确切大小,单位是bytes。 > 改为off后,显示出文件的大概大小,单位是kB或者MB或者GB > autoindex\_localtime on; > 默认为off,显示的文件时间为GMT时间。 > 改为on后,显示的文件时间为文件的服务器时间 ### 错误码原因和解决方案 #### 400 bad request 错误的原因和解决办法 配置nginx.conf相关设置如下. ```bash client_header_buffer_size 16k; large_client_header_buffers 4 64k; ``` 根据具体情况调整,一般适当调整值就可以。 #### Nginx 502 Bad Gateway错误 ```bash proxy_next_upstream error timeout invalid_header http_500 http_503; ``` 或者尝试设置: ```bash large_client_header_buffers 4 32k; ``` #### Nginx出现的413 Request Entity Too Large错误 这个错误一般在上传文件的时候会出现, 编辑Nginx主配置文件Nginx.conf,找到http{}段,添加 ```bash client_max_body_size 10m; //设置多大根据自己的需求作调整. ``` 如果运行php的话这个大小client_max_body_size要和php.ini中的如下值的最大值一致或者稍大,这样就不会因为提交数据大小不一致出现的错误。 ```bash post_max_size = 10M upload_max_filesize = 2M ``` #### 解决504 Gateway Time-out(nginx) 遇到这个问题是在升级discuz论坛的时候遇到的 **一般看来, 这种情况可能是由于nginx默认的fastcgi进程响应的缓冲区太小造成的, 这将导致fastcgi进程被挂起, 如果你的fastcgi服务对这个挂起处理的不好, 那么最后就极有可能导致504 Gateway Time-out** 现在的网站, 尤其某些论坛有大量的回复和很多内容的, 一个页面甚至有几百K。 **默认的fastcgi进程响应的缓冲区是8K,** 我们可以设置大点 在nginx.conf里, 加入: ```bash fastcgi_buffers 8 128k ``` 这表示设置fastcgi缓冲区为8×128k 当然如果您在进行某一项即时的操作, 可能需要nginx的 **超时参数调大点** ,例如设置成60秒: ```bash send_timeout 60; ``` 只是调整了这两个参数, 结果就是没有再显示那个超时, 可以说效果不错, 但是也可能是由于其他的原因, 目前关于nginx的资料不是很多, 很多事情都需要长期的经验累计才有结果. ### location用法 ```bash location = / { # 精确匹配 / ,主机名后面不能带任何字符串 [ configuration A ] } location / { # 因为所有的地址都以 / 开头,所以这条规则将匹配到所有请求 # 但是正则和最长字符串会优先匹配 [ configuration B ] } location /documents/ { # 匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索 # 只有后面的正则表达式没有匹配到时,这一条才会采用这一条 [ configuration C ] } location ~ /documents/Abc { # 匹配任何以 /documents/Abc 开头的地址,匹配符合以后,还要继续往下搜索 # 只有后面的正则表达式没有匹配到时,这一条才会采用这一条 [ configuration CC ] } location ^~ /images/ { # 匹配任何以 /images/ 开头的地址,匹配符合以后,停止往下搜索正则,采用这一条。 [ configuration D ] } location ~* \.(gif|jpg|jpeg)$ { # 匹配所有以 gif,jpg或jpeg 结尾的请求 # 然而,所有请求 /images/ 下的图片会被 config D 处理,因为 ^~ 到达不了这一条正则 [ configuration E ] } location /images/ { # 字符匹配到 /images/,继续往下,会发现 ^~ 存在 [ configuration F ] } location /images/abc { # 最长字符匹配到 /images/abc,继续往下,会发现 ^~ 存在 # F与G的放置顺序是没有关系的 [ configuration G ] } location ~ /images/abc/ { # 只有去掉 config D 才有效:先最长匹配 config G 开头的地址,继续往下搜索,匹配到这一条正则,采用 [ configuration H ] } location ~* /js/.*/\.js ``` > 已=开头表示精确匹配 > 如 A 中只匹配根目录结尾的请求,后面不能带任何字符串。 > ^~开头表示uri以某个常规字符串开头,不是正则匹配 > ~ 开头表示区分大小写的正则匹配; > ~* 开头表示不区分大小写的正则匹配 > / 通用匹配, 如果没有其它匹配,任何请求都会匹配到 ### 优先级 > (location =) > (location 完整路径) > (location ^~ 路径) > (location ~,~* 正则顺序) > (location 部分起始路径) > (/) 上面的匹配结果 按照上面的location写法,以下的匹配示例成立: ```bash * / -> config A 精确完全匹配,即使/index.html也匹配不了 * /downloads/download.html -> config B 匹配B以后,往下没有任何匹配,采用B * /images/1.gif -> configuration D 匹配到F,往下匹配到D,停止往下 * /images/abc/def -> config D 最长匹配到G,往下匹配D,停止往下 你可以看到 任何以/images/开头的都会匹配到D并停止,FG写在这里是没有任何意义的,H是永远轮不到的,这里只是为了说明匹配顺序 * /documents/document.html -> config C 匹配到C,往下没有任何匹配,采用C * /documents/1.jpg -> configuration E 匹配到C,往下正则匹配到E * /documents/Abc.jpg -> config CC 最长匹配到C,往下正则顺序匹配到CC,不会往下到E ``` #### 实际使用中三个匹配规则定义 所以实际使用中,个人觉得至少有三个匹配规则定义,如下: ```bash #直接匹配网站根,通过域名访问网站首页比较频繁,使用这个会加速处理,官网如是说。 #这里是直接转发给后端应用服务器了,也可以是一个静态首页 # 第一个必选规则 location = / { proxy_pass http://tomcat:8080/index } # 第二个必选规则是处理静态文件请求,这是nginx作为http服务器的强项 # 有两种配置模式,目录匹配或后缀匹配,任选其一或搭配使用 location ^~ /static/ { root /webroot/static/; } location ~* \.(gif|jpg|jpeg|png|css|js|ico)$ { root /webroot/res/; } #第三个规则就是通用规则,用来转发动态请求到后端应用服务器 #非静态文件请求就默认是动态请求,自己根据实际把握 #毕竟目前的一些框架的流行,带.php,.jsp后缀的情况很少了 location / { proxy_pass http://tomcat:8080/ } ``` 参考 http://tengine.taobao.org/book/chapter_02.html http://nginx.org/en/docs/http/ngx_http_rewrite_module.html ### 常用正则 > . : 匹配除换行符以外的任意字符 > ? : 重复0次或1次 > + : 重复1次或更多次 > * : 重复0次或更多次 > \d :匹配数字 > ^ : 匹配字符串的开始 > $ : 匹配字符串的结束 > {n} : 重复n次 > {n,} : 重复n次或更多次 > [c] : 匹配单个字符c > [a-z] : 匹配a-z小写字母的任意一个 ### rewrite **Rewrite规则** rewrite功能就是, **使用nginx提供的全局变量或自己设置的变量,结合正则表达式和标志位实现url重写以及重定向。** rewrite只能放在 **server{},location{},if{}** 中,并且 **只能对域名后边的除去传递的参数外的字符串起作用** ,例如http://seanlook.com/a/we/index.php?id=1&u=str只对/a/we/index.php重写。语法rewrite regex replacement [flag]; **如果相对域名或参数字符串起作用,可以使用全局变量匹配,也可以使用proxy_pass反向代理。** 表明看rewrite和location功能有点像, **都能实现跳转,主要区别在于rewrite是在同一域名内更改获取资源的路径,而location是对一类路径做控制访问或反向代理,可以proxy_pass到其他机器。** 很多情况下rewrite也会写在location里,它们的执行顺序是: 1. 执行server块的rewrite指令 2. 执行location匹配 3. 执行选定的location中的rewrite指令 如果其中某步URI被重写,则重新循环执行1-3,直到找到真实存在的文件; **循环超过10次,则返回500 Internal Server Error错误** 。 **write实例** ```bash http { # 定义image日志格式 log_format imagelog '[$time_local] ' $image_file ' ' $image_type ' ' $body_bytes_sent ' ' $status; # 开启重写日志 rewrite_log on; server { root /home/www; location / { # 重写规则信息 error_log logs/rewrite.log notice; # 注意这里要用‘’单引号引起来,避免{} rewrite '^/images/([a-z]{2})/([a-z0-9]{5})/(.*)\.(png|jpg|gif)$' /data?file=$3.$4; # 注意不能在上面这条规则后面加上“last”参数,否则下面的set指令不会执行 set $image_file $3; set $image_type $4; } location /data { # 指定针对图片的日志格式,来分析图片类型和大小 access_log logs/images.log mian; root /data/images; # 应用前面定义的变量。判断首先文件在不在,不在再判断目录在不在,如果还不在就跳转到最后一个url里 try_files /$arg_file /image404.html; } location = /image404.html { # 图片不存在返回特定的信息 return 404 "image not found\n"; } } ``` ### 全局变量 #### 可以用作if判断的全局变量 下面是可以用作if判断的全局变量 > $args: #这个变量等于请求行中的参数,同$query_string > $content_length: 请求头中的Content-length字段。 > $content_type: 请求头中的Content-Type字段。 > $document_root: 当前请求在root指令中指定的值。 > $host: 请求主机头字段,否则为服务器名称。 > $http_user_agent: 客户端agent信息 > $http_cookie: 客户端cookie信息 > $limit_rate: 这个变量可以限制连接速率。 > $request_method: 客户端请求的动作,通常为GET或POST。 > $remote_addr: 客户端的IP地址。 > $remote_port: 客户端的端口。 > $remote_user: 已经经过Auth Basic Module验证的用户名。 > $request_filename: 当前请求的文件路径,由root或alias指令与URI请求生成。 > $scheme: HTTP方法(如http,https)。 > $server_protocol: 请求使用的协议,通常是HTTP/1.0或HTTP/1.1。 > $server_addr: 服务器地址,在完成一次系统调用后可以确定这个值。 > $server_name: 服务器名称。 > $server_port: 请求到达服务器的端口号。 > $request_uri: 包含请求参数的原始URI,不包含主机名,如:”/foo/bar.php?arg=baz”。 > $uri: 不带请求参数的当前URI,$uri不包含主机名,如”/foo/bar.html”。 > $document_uri: 与$uri相同。 #### 例:http://localhost:88/test1/test2/test.php ```bash $host:localhost $server_port:88 $request_uri:http://localhost:88/test1/test2/test.php $document_uri:/test1/test2/test.php $document_root:/var/www/html $request_filename:/var/www/html/test1/test2/test.php ``` ### if语句块 #### if判断指令 语法为 **if(condition){...}** ,对给定的条件condition进行判断。如果为真,大括号内的rewrite指令将被执行,if条件(conditon)可以是如下任何内容: - 当表达式只是一个变量时,如果值为空或任何以0开头的字符串都会当做false - 直接比较变量和内容时,使用=或!= - ~正则表达式匹配,~*不区分大小写的匹配,!~区分大小写的不匹配 > -f和!-f用来判断是否存在文件 > -d和!-d用来判断是否存在目录 > -e和!-e用来判断是否存在文件或目录 > -x和!-x用来判断文件是否可执行 例如: ```bash if ($http_user_agent ~ MSIE) { rewrite ^(.*)$ /msie/$1 break; } //如果UA包含"MSIE",rewrite请求到/msid/目录下 if ($http_cookie ~* "id=([^;]+)(?:;|$)") { set $id $1; } //如果cookie匹配正则,设置变量$id等于正则引用部分 if ($request_method = POST) { return 405; } //如果提交方法为POST,则返回状态405(Method not allowed)。return不能返回301,302 if ($slow) { limit_rate 10k; } //限速,$slow可以通过 set 指令设置 if (!-f $request_filename){ break; proxy_pass http://127.0.0.1; } //如果请求的文件名不存在,则反向代理到localhost 。这里的break也是停止rewrite检查 if ($args ~ post=140){ rewrite ^ http://example.com/ permanent; } //如果query string中包含"post=140",永久重定向到example.com location ~* \.(gif|jpg|png|swf|flv)$ { valid_referers none blocked www.jefflei.com www.leizhenfang.com; if ($invalid_referer) { return 404; } //防盗链 } ``` ### https **定义一个新的server,配置如下,必须的配置有listen ,server_name, ssl ,ssl_certificate, ssl_certificate_key,一般配置的时候我都是直接复制,然后改主机名,证书私钥文件,日志路径,root的根目录这几项。 如果想让访问80的转到443,可用rewrite语句** ```bash listen 443; server_name agent.t.jlhcar.com; ssl on; ssl_certificate, "/usr/local/certificate/xxxx.pem";\\证书 ssl_certificate_key "/usr/local/certificate/xxxx.key";\\私钥 ssl_session_cache shared:SSL:1m; ssl_session_timeout 10m; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; ssl_prefer_server_ciphers on; ssl_protocols TLSv1 TLSv1.1 TLSv1.2;\\协议 ... //日志以及root根目录的其他配置 ``` ```bash server { listen 80; server_name www.example.com rewrite ^/(.*)$ https://www.example.com/$1; } ``` ### php后端处理(fast-cgi) ```bash location ~ \.php($|/) { fastcgi_pass unix:/dev/shm/php-fpm.unix; //最重要的一项,根据实际情况来配置(根据php的配置文件listen的配置来配置) fastcgi_index index.php; fastcgi_split_path_info ^(.+\.php)(.*)$; fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi.conf; } ``` ### flag标志位 - last: 相当于Apache的[L]标记,表示完成rewrite - break: 停止执行当前虚拟主机的后续rewrite指令集 - redirect: 返回302临时重定向,地址栏会显示跳转后的地址 - permanent: 返回301永久重定向,地址栏会显示跳转后的地址 因为301和302不能简单的只返回状态码,还必须有重定向的URL,这就是return指令无法返回301,302的原因了。这里 last 和 break 区别有点难以理解: 1. last一般写在server和if中,而break一般使用在location中 2. last不终止重写后的url匹配,即新的url会再从server走一遍匹配流程,而break终止重写后的匹配 3. break和last都能组织继续执行后面的rewrite指令 ### 过期功能(浏览器缓存 性能优化) **expires(配置在nginx.conf中的server模块中)** > 为用户访问网站的内容设定一个过期时间,当用户第一次访问到这些内容时,会把这些内容存储在用户浏览器本地,这样用户第二次及之后继续访问该网站,浏览器就会检查已经缓存在用户浏览器本地的内容,就不会去浏览器下载了,直到缓存的内容过期或者被清除为止。 #### 根据扩展名进行判断 ```bash location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ { root /var/www/static; expires 365d; 当用户访问网站URL结尾的文件扩展名为上述指定类型的图片时,设置缓存365天。 } location ~ .*\.(js|css)?$ { root /var/www/static; expires 30d; #当用户访问网站URL结尾的文件扩展名为js、css类型的元素时,设置缓存30天。 } …… ``` #### 根据URI中的路径(目录)进行判断,添加expires功能范例 ```bash location ~ ^/ (images|javascript|js|css|flash|media|static)/ { expires 360d; } ``` #### 单个文件添加expires功能范例 ```bash location ~(robots.txt){ expires 7d; #给robots.txt机器人文件设置过去时间,在设置的期间内不记录404错误日志。 break;} ``` #### Nginx expires功能缺点及解决方法 当网站被缓存的界面或数据更新了,此时用户端看到还是旧的已经缓存的内容,这样就会影响到用户体验,解决方法如下: - 对于 **经常需要变动的图片等文件** ,可以 **缩短对象缓存时间。** - 当网站改版或更新时,可以在服务器将缓存的对象改名(代码程序) - 对于网站的图片、附件,一般不会被用户直接修改,用户层面上的修改图片,实际上个是重新传到服务器,虽然内容一样,但是会产生一个新的图片名称。 - 网站改版升级会修改js、css等样式文件,若改版时对这些样式文件中的元素改了名,会使得前端的CDN及用户端需要重新缓存内容。 ### gzip压缩 #### 配置nginx gzip压缩实现性能优化 **图片、视频(流媒体)等文件尽量不要压缩** ,因为这些文件大多都是经过压缩的,如果再压缩很可能不会减小或减小很少,或者有可能增大,而在压缩时还会消耗大量的CPU、内存资源 ```bash gzip on; #表示开启压缩功能 gzip_min_length 1k; #表示允许压缩的页面最小字节数,页面字节数从header头的Content-Length中获取。默认值是0,表示不管页面多大都进行压缩,建议设置成大于1K。如果小于1K可能会越压越大 gzip_buffers 432k; #压缩缓存区大小 gzip_http_version 1.1; #压缩版本 gzip_comp_level 9; #压缩比率 gzip_types text/css text/xml application/javascript; #指定压缩的类型 gzip_vary on; #vary header支持 ``` ### 会话保持时间 用户和服务器建立连接后客户端分配keep-alive链接超时时间,服务器将在这个超时时间过后关闭链接,我们将它设置低些可以让ngnix持续工作的时间更长,1.8.1默认为65秒,一般不超过120秒。 ```bash keepalive_timeout 65 60; #后面的60为发送给客户端应答报文头部中显示的超时时间设置为60s:如不设置客户端将不显示超时时间。 Keep-Alive:timeout=60 #浏览器收到的服务器返回的报文 如果设置为0表示关闭会话保持功能,将如下显示: Connection:close #浏览器收到的服务器返回的报文 ``` ### 配置nginx worker进程最大打开文件数 ```bash worker_rlimit_nofile 65535; ``` ### sendfile 配置允许sendfile方式传输文件: > 是由后端程序负责把源文件打包加密生成目标文件,然后程序读取目标文件返回给浏览器;这种做法有个致命的缺陷就是占用大量后端程序资源,如果遇到一些访客下载速度巨慢,就会造成大量资源被长期占用得不到释放(如后端程序占用的CPU/内存/进程等),很快后端程序就会因为没有资源可用而无法正常提供服务。通常表现就是 nginx报502错误,而sendfile打开后配合location可以实现有nginx检测文件使用存在,如果存在就有nginx直接提供静态文件的浏览服务,因此可以提升服务器性能. ```bash sendfile on; # 可以配置在http、server或者location模块,配置如下: sendfile_max_chunk 512k; #Nginxg工作进程每次调用sendfile()传输的数据最大不能超出这个值,默认值为0表示无限制,可以设置在http/server/location模块中。 ``` ### 单个工作进程的最大连接数 配置单个工作进程的最大连接数: > 通过worker_connections number;进行设置,numebr为整数,number的值不能大于操作系统能打开的最大的文件句柄数,使用ulimit -n可以查看当前操作系统支持的最大文件句柄数,默认为为1024. ```bash events { worker_connections 102400; #设置单个工作进程最大连接数102400 } ``` ### 选择事件驱动模型 Nginx支持众多的事件驱动,比如 **select、poll、epoll** ,只能设置在 **events模块** 中设置: ```bash events { accept_mutex on; multi_accept on; use epoll; #使用epoll事件驱动,因为epoll的性能相比其他事件驱动要好很多 } ``` ### 隐藏ngxin版本号 隐藏ngxin版本号: > 当前使用的nginx可能会有未知的漏洞,如果被黑客使用将会造成无法估量的损失,但是我们可以将nginx的版本隐藏,如下: ```bash server_tokens off; #在http 模块当中配置 ``` ### 网络连接的优化 > 只能在events模块设置,用于防止在同一一个时刻只有一个请求的情况下,出现多个睡眠进程会被唤醒但只能有一个进程可获得请求的尴尬,如果不优化,在多进程的nginx会影响以部分性能。 ```bash events { accept_mutex on; #优化同一时刻只有一个请求而避免多个睡眠进程被唤醒的设置,on为防止被同时唤醒,默认为off,因此nginx刚安装完以后要进行适当的优化。 } ``` ### 缓存原理及机制 #### 什么是Nginx缓存? Nginx基于 **Proxy Store** 实现,使用Nginx的 **http_proxy模块** 可以 **实现类似于squid的缓存功能** 。当启用缓存时, **Nginx会将相应数据保存在磁盘缓存中,只要缓存数据尚未过期,就会使用缓存数据来响应客户端的请求** 。 #### 如何启用缓存? ##### proxy_cache_path Nginx **启用缓存需要在最顶层的http节点下配置proxy_cache_path命令** 。我们先看看proxy_cache_path命令的语法结构: > proxy_cache_path /data/cache keys_zone=niyueling:10m; 可以看到 **proxy_cache_path命** 令一共 **包含两个参数,第一个参数指定缓存保存的本地路径,第二个参数定义缓存数据的共享内存区域的名称和内存区大小** 。Nginx启动后, **缓存加载程序只进行加载一次,加载时会将缓存的元数据加载到共享内存区域** ,但是如果一次加载整个缓存全部内容可能会使Nginx刚启动的前几分钟性能消耗严重,大幅度降低Nginx的性能。所以可以在proxy_cache_path命令中 **配置缓存迭代加载** 。缓存迭代加载一共可以 **设置三个参数:** - loader_threshold - 迭代的持续时间,以毫秒为单位(默认为200) - loader_files - 在一次迭代期间加载的最大项目数(默认为100) - loader_sleeps - 迭代之间的延迟(以毫秒为单位)(默认为50) 我们可以看下一个小例子: > proxy_cache_path /data/cache keys_zone=niyueling:10m loader_threshold=300 loader_files=200; ##### proxy_cache 在这个例子中缓存迭代加载可以持续300毫秒或者直到加载满200个项目。在http节点下设置完proxy_cache_path命令,下一步在虚拟服务器配置中配置proxy_cache命令,我们可以看看proxy_cache命令的语法结构: > proxy_cache niyue ##### proxy_cache_methodsling; 可以看到proxy_cache命令很简单,就是指定了我们刚才配置的内存区。但是这里有一点需要额外注意的是:我们刚才通过 **配置proxy_cache_path命令的keys_zone参数配置内存区大小为10m,这并不会限制缓存数据的大小** ,实际上缓存数据是存储在文件系统中的特定文件的元数据副本。 **如果想要限制缓存数据的上限,则需要在proxy_cache_path命令中添加max_size参数设置缓存数据上限。** 说完了proxy_cache命令。我们接着看看下一个命令:proxy_cache_methods,我们看下该命令语法结构: > proxy_cache_methods[GET HEAD POST]; ##### proxy_cache_valid 在虚拟服务器下配置 **proxy_cache_methods** 命令可以 **指定该虚拟服务器下什么类型的HTTP方法可以被缓存。默认情况下GET请求及HEAD请求会被缓存,而POST请求不会被缓存。** 接下来看看另外一个常见的命令: **proxy_cache_valid** ,先贴下该命令语法结构: proxy_cache_valid reply_code [reply_code...] time; 这个命令很有意思,在虚拟服务器下设置该命令,它可以针对不同状态码的响应数据设置不同的缓存时间,我们可以看个简单的小例子: ```bash proxy_cache_valid 200 10m ; proxy_cache_valid 404 1m ; proxy_cache_valid 302 5m ; ``` 我们通过上面的命令就可以 **设置200状态码的缓存时间为10分钟,302重定向的缓存时间为5分钟,404的缓存时间为1分钟** 。如果想为 **所有状态码定义相同缓存时间,就可以使用any作为第一个参数:** > proxy_cache_valid any 5m; ##### proxy_cache_bypass 接下来看看下一个命令:proxy_cache_bypass。一样先看下语法结构: > proxy_cache_bypass cookie_nocachearg_nocache$arg_comment; 这个命令可以配置不会向客户端响应缓存,而是直接将请求转发给后端服务进行请求数据。 **可以通过上述命令配置需要绕过缓存的请求URL** ,也就是说URL中包含该配置的值,则这次请求会直接跳过缓存直接请求后端服务去获取数据。 ##### proxy_cache_min_uses 接下来还有最后一个比较常用的命令:proxy_cache_min_uses。先贴下语法结构: > proxy_cache_min_uses 2; 这个命令可以 **设置当某请求最少响应几次后会被缓存** 。若我设置为2则表示每个请求 **最少被请求2次后会加入到缓存中** 。 #### Nginx清除缓存 **如果缓存过期则需要从缓存中删除过期的缓存文件,防止新旧缓存出现交错出错,当Nginx接收到自定义HTTP头或者PURGE请求时,缓存将会被清除。** ##### 配置缓存清除 我们在HTTP节点下创建一个新变量$purge_method来标识使用PURGE方法的请求并删除匹配的URL。 ```bash http { map request_methodpurge_method { PURGE 1; default 0; } } ``` 进入虚拟服务器配置, **在location中配置高速缓存,并且指定缓存清除请求命令proxy_cache_purge。** ```bash server { listen 80; server_name www.niyueling.cn; location / { proxy_cache niyueling; proxy_cache_purge $purge_method; } } ``` ##### 发送清除命令 配置proxy_cache_purge指令后需要发送PURGE请求来清除缓存。例如我们使用PURGE方式请求url: ###### PURGE www.niyueling.cn/getArticle 则getArticle对应的缓存中的数据将被删除。但是,这些高速缓存数据不会从缓存中完全删除,它们将保留在磁盘上,直到它们被删除为非活动状态,或由缓存清除进程处理。 ##### 限制IP访问清除命令 清除缓存这种命令一般需要权限才可进行操作,所以我们一般需要配置允许发送缓存清除请求的IP地址: ```bash geo purge_allowed { default 0; 49.235.28.88 1; 192.168.1.100/24 1; } maprequest_method purge_method { PURGEpurge_allowed; default 0; } ``` 当Nginx接收到清除缓存请求时,Nginx检查客户端IP地址,若IP地址已经获得清除缓存权限,则purge_method设置为purge_allowed,值为1表示允许清除缓存,值为0表示表示IP地址未获得权限。 ##### 从缓存中完全删除文件 刚才说过了高速缓存数据不会从缓存中完全删除,它们将保留在磁盘上,直到它们被删除为非活动状态,或由缓存清除进程处理。要完全删除与getArticle相匹配的缓存数据,需要在proxy_cache_path添加参数purger,该参数表示永久的遍历所有缓存条目,并删除与通配符相匹配的条目。 ###### proxy_cache_path /data/cache keys_zone=niyueling:10m purger=on; ##### 字节缓存 当我们请求一个大文件时,因为请求比较耗时,当有下一个请求来临时将不得不等待整个大文件被下载并放入高速缓存。 **Nginx用缓存片模块填充高速缓存** 。可以将大文件分为较小的切片,每个范围请求选择将覆盖所请求范围的特定切片,并且如果此范围切片仍未缓存,就将其放入缓存中。 **启用字节范围缓存需要注意两个条件是否满足** : - 确保Nginx是使用模块编译的。 - 使用slice指令指定切片的大小。 ###### 可以使用slice命令指定切片大小: ```bash location / { slice 1m; } ``` 使用slice指令指定切片大小时应注意切片大小应适当调整,使切片快速下载。因为切片大小指定太小可能会导致内存使用量过多和大量打开的文件描述符,切片大小指定太大的值可能会导致请求延迟。 ###### 接着将$slice_range变量加入到缓存键中: > proxy_cache_key uriis_argsargsslice_range; ###### 使用206状态代码缓存响应,缓存有效期30m: > proxy_cache_valid 206 30m; ###### 然后设置Range头传递$slice_range变量来将传递范围请求: > proxy_set_header Range $slice_range; ###### 字节缓存小案例: ```bash location / { slice 1m; proxy_cache niyueling; proxy_cache_key uriis_argsargsslice_range; proxy_set_header Range $slice_range; proxy_cache_valid 206 30m; } ``` ###### 缓存清除小案例 ```bash http { proxy_cache_path /data/cache keys_zone=niyueling:10m purger=on; map request_methodpurge_method { PURGE 1; default 0; } server { listen 80; server_name www.niyueling.cn; location / { proxy_cache niyueling; proxy_cache_purge $purge_method; } } geo $purge_allowed { default 0; 49.235.28.88 1; 192.168.1.100/24 1; } map request_methodpurge_method { PURGE $purge_allowed; default 0; } } ``` ### 限流 在当今流量徒增的互联网时代,很多业务场景都会涉及到高并发。这个时候 **接口进行限流是非常有必要的,而限流是Nginx最有用的特性之一,而且也是最容易被错误配置的特性之一。** 本篇文章主要讲讲Nginx如何对接口进行限流。 #### 为什么需要限流? 开源人员可以通过限流限制访问速度来防止外部暴力扫描,或者减少密码被暴力破解的可能性。也可以解决流量突发问题(如线上活动导致访问量突增)。用一句话来概括就是说限流是用于保护服务器不会因为承受不住同一时刻的大量并发请求而宕机。 #### Nginx限流主要分为两种方式: 1. 限制访问频率 2. 限制并发连接数 接下来我们分别来看看Nginx的两种限流方式: ##### 限制访问频率 限制访问频率其实需要分成两种情况:正常情况下进行访问频率限制以及流量突发情况下进行访问频率限制。我们分别看看这两种情况下Nginx是如何进行处理的: ###### 正常流量限制访问频率 **Nginx中使用ngx_http_limit_req_module模块来限制的访问频率** ,限制的原理实质是 **基于漏桶算法原理来实现的** 。在nginx.conf配置文件中 **可以使用limit_req_zone命令及limit_req命令限制单个IP的请求处理频率。** 我们可以先来看看这两个命令的语法结构: > limit_req_zone key zone rate 对于上面语法结构的参数简单做下解释: > key: 定义需要限流的对象。 > zone: 定义共享内存区来存储访问信息。 > rate: 用于设置最大访问速率。 接下来我们看个简单的例子: ```bash http { limit\_req\_zone $binary\_remote\_addr zone=myLimit:10m rate=3r/s; } server { location / { limit\_req zone=myLimit; rewrite / [http://www.niyueling.cn](https://links.jianshu.com/go?to=http%3A%2F%2Fwww.niyueling.cn) permanent; } } ``` 对配置简单做下解释: 上面binary_remote_addr就是key,表示基于客户端ip(remote_addr)进行限流,binary_表示压缩内存占用量。定义了一个大小为10M,名称为myLimit的内存区,用于存储IP地址访问信息。rate设置IP访问频率, **rate=5r/s表示每秒只能处理每个IP地址的5个请求。Nginx限流是按照毫秒级为单位的,也就是说1秒处理5个请求会变成每200ms只处理一个请求。如果200ms内已经处理完1个请求,但是还是有有新的请求到达,这时候Nginx就会拒绝处理该请求。** ###### 突发流量限制访问频率 上面的配置一定程度可以限制访问频率,但是也存在着一个问题:如果突发流量超出请求被拒绝处理,无法处理活动时候的突发流量,这时候应该如何进一步处理呢?Nginx提供burst参数结合nodelay参数可以解决流量突发的问题,可以设置能处理的超过设置的请求数外能额外处理的请求数。我们可以将之前的例子 **添加burst参数以及nodelay参数:** ```bash http { limit\_req\_zone $binary\_remote\_addr zone=myLimit:10m rate=3r/s; } server { location / { limit\_req zone=myLimit burst=5 nodelay; rewrite / [http://www.niyueling.cn](https://links.jianshu.com/go?to=http%3A%2F%2Fwww.niyueling.cn) permanent; } } ``` 可以看到我在原有的 **location中的limit_req指令中添加了burst=5 nodelay** ,如果没有添加nodelay参数,则可以理解为预先在内存中占用了5个请求的位置,如果有5个突发请求就会按照200ms去依次处理请求,也就是1s内把5个请求全部处理完毕。如果1s内有新的请求到达也不会立即进行处理,因为紧急程度更低。这样实际上就会将额外的5个突发请求以200ms/个去依次处理,保证了处理速率的稳定,所以在处理突发流量的时候也一样可以正常处理。如果添加了nodelay参数则表示要立即处理这5个突发请求。 ##### 限制并发连接数 **Nginx中的ngx_http_limit_conn_module模块提供了限制并发连接数的功能,可以使用limit_conn_zone指令以及limit_conn执行进行配置。** 接下来我们可以通过一个简单的例子来看下: ```bash http { limit\_conn\_zone ![binary_remote_addr zone=myip:10m; limit_conn_zone](https://math.jianshu.com/math?formula=binary_remote_addr%20zone%3Dmyip%3A10m%3B%20limit_conn_zone)server\_name zone=myServerName:10m; } server { location / { limit\_conn myip 10; limit\_conn myServerName 100; rewrite / [http://www.niyueling.cn](https://links.jianshu.com/go?to=http%3A%2F%2Fwww.niyueling.cn) permanent; } } ``` **上面配置了单个IP同时并发连接数最多只能10个连接,并且设置了整个虚拟服务器同时最大并发数最多只能100个链接。** 当然,只有当请求的header被服务器处理后,虚拟服务器的连接数才会计数。刚才有提到过Nginx是基于漏桶算法原理实现的,实际上限流一般都是基于漏桶算法和令牌桶算法实现的。接下来我们来看看两个算法的介绍: ##### 漏桶算法 漏桶算法是网络世界中流量整形或速率限制时经常使用的一种算法,它的主要目的是控制数据注入到网络的速率,平滑网络上的突发流量。漏桶算法提供了一种机制,通过它,突发流量可以被整形以便为网络提供一个稳定的流量。也就是我们刚才所讲的情况。漏桶算法提供的机制实际上就是刚才的案例: **突发流量会进入到一个漏桶,漏桶会按照我们定义的速率依次处理请求,如果水流过大也就是突发流量过大就会直接溢出,则多余的请求会被拒绝。所以漏桶算法能控制数据的传输速率。** ##### 令牌桶算法 令牌桶算法是网络流量整形和速率限制中最常使用的一种算法。典型情况下,令牌桶算法用来控制发送到网络上的数据的数目,并允许突发数据的发送。Google开源项目Guava中的RateLimiter使用的就是令牌桶控制算法。 **令牌桶算法的机制如下:存在一个大小固定的令牌桶,会以恒定的速率源源不断产生令牌。如果令牌消耗速率小于生产令牌的速度,令牌就会一直产生直至装满整个令牌桶。** ##### 漏桶算法与令牌桶算法的区别 **两种算法都能够限制数据传输速率,但令牌桶还允许某种程度的突发传输。因为令牌桶算法只要令牌桶中存在令牌,那么就可以突发的传输对应的数据到目的地,所以更适合流量突发的情形下进行使用。** ### 日志配君 众所周知,线上如果出现事故我们通常都是查看日志去进行问题定位并且进行修复。使用好Nginx日志有利于我们线上进行修复异常问题。 **在Nginx中日志主要分为两种:access_log(访问日志)和error_log(错误日志)** 。通过 **查看access_log我们可以查看用户ip,浏览器信息及请求时间等信息,通过查看error_log我们可以查看线上出错的具体信息,可以帮助我们定位异常的原因。** 本篇文章主要带领大家详细了解Nginx如何配置日志。本文将会涉及到的日志配置指令: - access_log - log_format - open_log_file_cache - log_not_found - log_subrequest - rewrite_log - error_log #### access_log指令 首先,我们可以先看看access_log指令。access_log命令 **可以配置访问日志** 。我们可以先看下access_log指令的语法结构: > access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]]; # 设置访问日志 > access_log off; # 关闭访问日志 我们先来看看语法结构中的参数的含义: > path: 指定日志的存放位置 > format: 指定日志的格式,非必填,默认为预定义的combined > buffer:指定日志写入时的缓存大小,非必填,默认64k > gzip: 日志写入前先进行压缩 > flush: 设置缓存的有效期 > if: 设置条件判断,当天剑成立时才会写入日志 > off: 值为off表示不开启日志,值为on表示开启日志 access_log指令可以使用于http根节点,虚拟服务器server节点,上下文配置location以及limit_except中。无法在其他作用域使用access_log指令,否则Nginx会报错。我们可以看一个简单的配置access_log的小例子: > access_log /root/.pm2/logs/niyueling.log buffer=32k gzip flush=5m 这个配置指定日志存储路径为/root/.pm2/logs/niyueling.log,日志使用默认格式combined。日志缓存大小为32k,日志写入前会进行gzip压缩,缓存有效期为5分钟。 #### log_format指令 刚才有讲过如果未指定日志格式,Nginx会 **使用combined日志格式为默认格式。** combined日志格式默认使用格式为: > log_format combined 'remote_addr -remote_user [![time_local] ' '"](https://math.jianshu.com/math?formula=time_local] ' '")request" statusbody_bytes_sent ' '"http_referer" "http_user_agent"'; 但是如果不想使用combined日志格式,就可以使用log_format指令来自定义格式内容。log_format指令需要在http节点下进行配置。我们先来看下log_format指令的语法结构: > log_format name [escape=default|json] string; 我们先来看看log_format的参数对应的用法: > name: 指定日志格式名称,因为在access_log指令中需要指定日志格式 > escape: 设置字符编码方式,可以选择default或者json > string: 要写入日志的内容,可以有多个参数,可以使用Nginx变量。 下面贴一下log_format指令中常用的一些变量: **file** 我们可以接着看个自定义日志格式的小案例: ```bash http { log_format main 'remote_addr -remote_user [![time_local] "](https://math.jianshu.com/math?formula=time_local] ")request" ' '"status"body_bytes_sent "http_referer" ' '"http_user_agent" "http_x_forwarded_for" ' '"gzip_ratio" request_timebytes_sent $request_length'; server { server_name www.niyueling.cn; access_log /root/.pm2/logs/niyueling.log main; } } ``` #### open_log_file_cache指令 对于网站的访问记录,通常操作都是首先打开日志文件,然后写入日志记录,最后关闭文件。 **默认情况下日志文件不进行缓存的,我们可以通过open_log_file_cache指令设置日志文件缓存。** open_log_file_cache指令可以配置在http根节点,虚拟服务器server节点以及上下文location中。我们先看下open_log_file_cache指令的语法结构: > open_log_file_cache max=X [inactive=time] [min_uses=N] [valid=time]; > open_log_file_cache off; 首先先贴下参数对应的含义: > max: 设置缓存中的最大文件描述符 > inactive: 设置存活时间 > min_uses: 在存活时间内,日志文件最少被使用几次后将日志文件描述符写入缓存。 > valid: 设置检查频率 > off: 禁用日志缓存 可以看一个简单配置日志缓存的小例子: > open_log_file_cache max=100 inactive=30s valid=5m min_uses=3; #### log_not_found指令 这个命令 **用于指定是否在error_log错误日志中记录不存在的错误,如文件不存在等。** 默认值为是。我们可以先看下语法结构: > log_not_found on | off; log_not_found指令可以配置在http根节点,虚拟服务器server节点以及上下文location中。设置为on表示记录不存在的错误,设置为off表示不记录不存在的错误。 #### log_subrequest指令 log_subrequest指令用于指定在access_log访问日志中是否记录子请求的访问记录。默认情况为不记录,贴下语法结构: > log_subrequest on | off; log_subrequest指令可以配置在http根节点,虚拟服务器server节点以及上下文location中。设置为on表示记录子请求访问记录,设置为off表示不记录子请求访问记录。 #### rewrite_log指令 rewrite_log指令 **由ngx_http_rewrite_module模块提供服务,用来记录日志重写。** 可以在error_log错误日志中记录notice级别的重写日志。 **默认是不启用状态** ,贴下语法结构: > rewrite_log on | off; rewrite_log指令可以配置在http根节点,虚拟服务器server节点以及上下文location以及if条件判断中。设置为on表示在错误日志中记录notice级别的重写日志,设置为off表示在错误日志中不记录notice级别的重写日志。 #### error_log指令 error_log指令顾名思义,就是 **用来指定错误日志的,一般来说线上出现bug都是通过error_log日志来定位问题所在而加以解决的** 。error_log指令可以记录服务器和请求处理过程中的错误信息。我们先看下error_log指令的语法结构: > error_log file [level]; 参数含义其实很容易可以理解: > file: error_log 存放路径 > level: 日志级别,只有日志级别高于指定级别才会记录到error_log中 > error_log指令可以配置在http节点,main节点,虚拟服务器server节点以及上下文location中。 #### 日志切割 Nginx记录日志默认情况下是访问日志全部写入access_log中,错误日志全部写入error_log中。这样会导致日志文件原来越大,不利于查看日志分析问题异常,所以我们可以将日志以日期为单位进行切割。首先需要写一个脚本实现Nginx按天切割: ##### 日志保存位置 > base_path='/root/.pm2/logs/niyueling.log' ##### 获取当前年信息和月信息 > log_path=$(date -d yesterday +"%Y%m") ##### 获取昨天的日信息 > day=$(date -d yesterday +"%d") ##### 按年月创建文件夹 > mkdir -p base_path/log_path ##### 备份昨天的日志到当月的文件夹 > mv base_path/access.logbase_path/log_path/access_day.log ##### 输出备份日志文件名 > echo base_path/log_path/access_$day.log ##### 通过Nginx信号量控制重读日志 > kill -USR1 cat /opt/nginx/logs/nginx.pid ##### 然后给脚本添加可执行权限,最后添加Linux定时任务: > crontab -e ##### 每天凌晨两点半进行日志分割 > 30 02 0 * * * /root/.pm2/logs/splitLog.sh ##### 重启Linux定时任务 crond restart 通过上面的讲解差不多可以知道Nginx对于日志是如何进行配置的,实际上就是通过log_format配置日志格式,如果log_format中使用了Nginx变量,则可以通过open_log_file_cache指令来设置缓存提高性能。然后通过access_log进行设置访问日志,通过error_log指令设置错误日志。最后实现定时任务定时切割每天的日志,有利于我们后期维护。 ### 灰度发布 #### 根据ip实现灰度发布 在百度查自己公司的公网IP #### 原理 **同时把两个不同版本的代码拉成两个项目,根据ip来判断用户可以去哪个项目,灰度发布的项目目录指向高版本的项目,其他ip的所有用户仍然访问相对的低版本的项目。** #### nginx配置 ```bash server { listen 80; server_name mb.com; gzip on; charset utf-8; set $mulu /var/www/mb/dist ; if ($remote_addr = 1.2.3.4) { set $mulu /var/www/mr/build; } location / { root $mulu; index index.html; location / { try_files $uri $uri/ /index.html; } } } ``` ### 配置一键生成 #### 前因 关于Nginx部署、配置的文章网上已经发布过很多,包括我自己也私藏了不少还发布过两篇: [后端必备 Nginx 配置](https://juejin.cn/post/6844903942187384840) [前端必备 Nginx 配置](https://juejin.cn/post/6844903942262882318) 整理出来为的就是需要的时候,复制、粘贴就能使用。 然而千奇百怪的实际开发中,你肯定需要增删Nginx配置。你就得上网搜一下,复制粘贴出bug了又得调一下... 搞定还得保存下来以备后患。多了不好找还得整理...就搞得很麻烦 #### 后果 今天我给大家推荐一款"Nginx配置利器",配配变量就能一键生成常用配置。和繁琐低效配置说再见👋 ##### 网站链接: - [nginxconfig 在线配置网站](https://www.digitalocean.com/community/tools/nginx?global.app.lang=zhCN) - [nginxconfig github项目](https://github.com/digitalocean/nginxconfig.io) ##### nginxconfig 目前支持: - Angular、React、Vue、Node.js - PHP、Python - wordpress、Magento、Drupal - 缓存、Https、日志等各种配置... #### 使用 实现用户访问*.myweb.com域名自动跳转到myweb.com配置,并且开启http强制跳转到https的配置。 配置完之后,下方还有安装步骤指导你配置生效。交互体验相当好 生成配置/etc/nginx/sites-available/myweb.com.conf如下: ```bash server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name myweb.com; root /var/www/myweb.com/public; # SSL ssl_certificate /etc/letsencrypt/live/myweb.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/myweb.com/privkey.pem; ssl_trusted_certificate /etc/letsencrypt/live/myweb.com/chain.pem; # security include nginxconfig.io/security.conf; # index.html fallback location / { try_files $uri $uri/ /index.html; } # additional config include nginxconfig.io/general.conf; } # subdomains redirect server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name *.myweb.com; # SSL ssl_certificate /etc/letsencrypt/live/myweb.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/myweb.com/privkey.pem; ssl_trusted_certificate /etc/letsencrypt/live/myweb.com/chain.pem; return 301 https://myweb.com$request_uri; } # HTTP redirect server { listen 80; listen [::]:80; server_name .myweb.com; include nginxconfig.io/letsencrypt.conf; location / { return 301 https://myweb.com$request_uri; } } ``` 网站下方还罗列了推荐的nginx配置、安全配置...以作参考 /etc/nginx/nginx.conf ```bash # Generated by nginxconfig.io # https://nginxconfig.io/?0.domain=myweb.com&0.php=false&0.index=index.html&0.fallback_html user www-data; pid /run/nginx.pid; worker_processes auto; worker_rlimit_nofile 65535; events { multi_accept on; worker_connections 65535; } http { charset utf-8; sendfile on; tcp_nopush on; tcp_nodelay on; server_tokens off; log_not_found off; types_hash_max_size 2048; client_max_body_size 16M; # MIME include mime.types; default_type application/octet-stream; # logging access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log warn; # SSL ssl_session_timeout 1d; ssl_session_cache shared:SSL:10m; ssl_session_tickets off; # Diffie-Hellman parameter for DHE ciphersuites ssl_dhparam /etc/nginx/dhparam.pem; # Mozilla Intermediate configuration ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; # OCSP Stapling ssl_stapling on; ssl_stapling_verify on; resolver 1.1.1.1 1.0.0.1 8.8.8.8 8.8.4.4 208.67.222.222 208.67.220.220 valid=60s; resolver_timeout 2s; # load configs include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; } ``` /etc/nginx/nginxconfig.io/security.conf ```bash # security headers add_header X-Frame-Options "SAMEORIGIN" always; add_header X-XSS-Protection "1; mode=block" always; add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "no-referrer-when-downgrade" always; add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; # . files location ~ /\.(?!well-known) { deny all; } ``` #### 拓展 以上就满足日常开发需求啦。如果你压抑不住,想要展示你的高端操作。 你可以加入到项目本身开发中;nginxconfig项目本身是 **MIT** 开源协议,你也可以在此基础上迭代出自己的版本 ## 其他配置/案例 ### [全面认识Nginx](https://segmentfault.com/a/1190000039873208) ### [常用配置](https://segmentfault.com/a/1190000040054327) ### [小试牛刀!Nginx 搭建静态资源服务器](https://segmentfault.com/a/1190000040049216) ### [Nginx 五大常见应用场景](https://segmentfault.com/a/1190000039374787) ### [Web服务器王者之争:Apache vs Nginx](https://segmentfault.com/a/1190000038306006) ### [Nginx 又一牛X的功能!流量拷贝](https://segmentfault.com/a/1190000021894850) ### [构建高效安全的Nginx Web服务器](https://segmentfault.com/a/1190000022338115) ### [为什么站点访问慢?请收好这份 Web 服务器性能提升的总结](https://segmentfault.com/a/1190000022413603) 最后修改:2023 年 09 月 18 日 © 允许规范转载 赞 如果觉得我的文章对你有用,请随意赞赏