# Nginx详解 ## 一、HTTP协议 HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议。 ### 1、HTTP 工作原理 **HTTP协议通信流程** ![1561893004169](assets/1561893004169.png) www.baidu.com/index.html 静态页面 动态页面 python python-mysql api接口 mysql **HTTP是基于客户端/服务端(C/S)的架构模型**,通过一个可靠的链接来交换信息,是一个无状态的请求/响应协议。 **浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求**。一个HTTP"客户端"是一个应用程序(Web浏览器或其他任何客户端),通过连接到服务器达到向服务器发送一个或多个HTTP请求的目的。 **Web服务器根据接收到的请求后,向客户端发送响应信息**。一个HTTP"服务器"同样也是一个应用程序(通常是一个Web服务,如Apache Web服务器或IIS服务器等),通过接收客户端的请求并向客户端发送HTTP响应数据。 HTTP使用统一资源标识符(Uniform Resource Identifiers, URI)来传输数据和建立连接。 ```bash CGI 通用网关接口(Common Gateway Interface/CGI)描述了客户端和服务器程序之间传输数据的一种标准,可以让一个客户端,从网页浏览器向执行在网络服务器上的程序请求数据。CGI 独立于任何语言的,CGI 程序可以用任何脚本语言或者是完全独立编程语言实现,只要这个语言可以在这个系统上运行 ``` #### 关于URI 官方地址:[标识互联网上的内容 - HTTP | MDN (mozilla.org)](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/Identifying_resources_on_the_Web) ![image-20220613103532626](assets/image-20220613103532626.png) HTTP 请求的内容通称为"资源"。"资源"这一概念非常宽泛,它可以是你能够想到的任何格式。每个资源都由一个 (URI) 来进行标识。 URI包含URL,URN URL即统一资源定位符,它是 URI 的一种。可以是一份文档,一张图片,或所有其他。不仅标识了Web 资源,还指定了操作或者获取方式,同时指出了主要访问机制和网络位置。 URN是URI的一种,用特定命名空间的名字标识资源。使用URN可以在不知道其网络位置及访问方式的情况下讨论资源。 **例子** 这是一个URI:"http://bitpoetry.io/posts/hello.html#intro" ```http "http://" 定义访问资源的方式。 "bitpoetry.io/posts/hello.html" 是资源存放的位置。 "#intro" 是资源。 ``` URL是URI的一个子集,告诉我们访问网络位置的方式。上例URL应该如下所示: ```http http://bitpoetry.io/posts/hello.html ``` URN是URI的子集,包括名字(给定的命名空间内),但是不包括访问方式,如下所示: ```http bitpoetry.io/posts/hello.html#intro ``` #### URL统一资源标识符语法 **方案或协议** ![Protocol](assets/mdn-url-protocol@x2.png) ``` `http://`告诉浏览器使用何种协议。对于大部分 Web 资源,通常使用 HTTP 协议或其安全版本,HTTPS 协议。另外,浏览器也知道如何处理其他协议。例如, `mailto:` 协议指示浏览器打开邮件客户端;`ftp:`协议指示浏览器处理文件传输。常见方案见下表 ``` | 方案 | 描述 | | :---------- | :----------------------------------------------------------- | | data | [Data URIs](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/Data_URLs) | | file | 指定主机上文件的名称 | | ftp | [文件传输协议](https://developer.mozilla.org/en-US/docs/Glossary/FTP) | | http/https | [超文本传输协议/安全的超文本传输协议](https://developer.mozilla.org/en-US/docs/Glossary/HTTP) | | mailto | 电子邮件地址 | | ssh | 安全 shell | | tel | 电话 | | urn | 统一资源名称 | | view-source | 资源的源代码 | | ws/wss | (加密的)[WebSocket (en-US)](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) 连接 | **主机** ![Domaine Name](assets/mdn-url-domain@x2.png) ``` `www.example.com` 既是一个域名,也代表管理该域名的机构。它指示了需要向网络上的哪一台主机发起请求。当然,也可以直接向主机的 [IP address](https://developer.mozilla.org/zh-CN/docs/Glossary/IP_Address) 地址发起请求。但直接使用 IP 地址的场景并不常见。 ``` **端口** ![Port](assets/mdn-url-port@x2.png) ``` :80` 是端口。它表示用于访问 Web 服务器上资源的技术“门”。如果访问的该 Web 服务器使用 HTTP 协议的标准端口(HTTP 为 80,HTTPS 为 443)授予对其资源的访问权限,则通常省略此部分。否则端口就是 URI 必须的部分。 ``` **路径** ![Path to the file](assets/mdn-url-path@x2.png) ``` `/path/to/myfile.html` 是 Web 服务器上资源的路径。在 Web 的早期,类似这样的路径表示 Web 服务器上的物理文件位置。现在,它主要是由没有任何物理实体的 Web 服务器抽象处理而成的。 ``` **查询** ![Parameters](assets/mdn-url-parameters@x2.png) ``` `?key1=value1&key2=value2` 是提供给 Web 服务器的额外参数。这些参数是用 & 符号分隔的键/值对列表。Web 服务器可以在将资源返回给用户之前使用这些参数来执行额外的操作。每个 Web 服务器都有自己的参数规则,想知道特定 Web 服务器如何处理参数的唯一可靠方法是询问该 Web 服务器所有者。 ``` **片段** ![Anchor](assets/mdn-url-anchor@x2.png) ``` `#SomewhereInTheDocument` 是资源本身的某一部分的一个锚点。锚点代表资源内的一种“书签”,它给予浏览器显示位于该“加书签”点的内容的指示。 例如,在 HTML 文档上,浏览器将滚动到定义锚点的那个点上;在视频或音频文档上,浏览器将转到锚点代表的那个时间。值得注意的是 # 号后面的部分,也称为片段标识符,永远不会与请求一起发送到服务器。 ``` ### 2、HTTP的特点 **HTTP是无连接的** ​ 无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。 **HTTP是媒体独立的** ​ 只要客户端和服务器知道如何处理的数据内容,任何类型的数据都可以通过HTTP发送。客户端以及服务器指定使用适合的MIME-type内容类型。 **HTTP是无状态的** ​ HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息则它必须重传。 ### 3、客户端请求消息 客户端发送一个HTTP请求到服务器的请求消息包括以下格式:请求行(request line)、请求头部(header)、空行和请求数据四个部分组成,下图给出了请求报文的一般格式。 ![1561893148999](assets/1561893148999.png) ### 4、服务器响应消息 HTTP响应也由四个部分组成,分别是:状态行、消息报头、空行和响应正文。 ![1561893177737](assets/1561893177737.png) **实例** 下面实例是一点典型的使用GET来传递数据的实例: 客户端请求: ```shell # curl -v http://www.testpm.cn Connected to www.testpm.cn (47.244.247.240) port 80 (#0) > GET /hello.txt HTTP/1.1 # 请求方式与版本协议。 > User-Agent: curl/7.29.0 #用什么客户端访问 > Host: www.testpm.cn #主机名,域名。主机和端口号, > Accept: */* #匹配什么文件类型,“*” 是通用匹配。匹配所有类型 ``` 服务端响应: ```shell < HTTP/1.1 200 OK # 请求返回的状态码 < Server: nginx/1.16.0 # 请求的服务和版本号 < Date: Thu, 04 Jul 2019 08:19:40 GMT # 当前时间,北京时间为GMT+8小时 < Content-Type: text/plain # mime类型,test/plain:普通文本,比如image/png...、video < Content-Length: 12 # 内容的长度 < Last-Modified: Thu, 04 Jul 2019 08:13:25 GMT #最后修改时间 < Connection: keep-alive #是否支持长连接 < ETag: "5d1db525-c" # 标识,每次访问如果与最开始的值一样返回304否则校验不一致返回200 < Accept-Ranges: bytes # 接受的范围单位 ``` 输出结果: ```shell hello world ``` ### 5、HTTP 请求方法 根据HTTP标准,HTTP请求可以使用多种请求方法。 ```bash HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法。 HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法。 ``` ![1561896279402](assets/1561896279402.png) ### 6、HTTP 响应头信息 HTTP响应头提供了关于请求,响应或者其他的发送实体的信息。 | 应答头 | 说明 | | ---------------- | ------------------------------------------------------------ | | Allow | 服务器支持哪些请求方法(如GET、POST等)。 | | Content-Encoding | 文档的编码(Encode)方法。只有在解码之后才可以得到Content-Type头指定的内容类型。利用gzip压缩文档能够显著地减少HTML文档的下载时间。Java的GZIPOutputStream可以很方便地进行gzip压缩,但只有Unix上的Netscape和Windows上的IE 4、IE 5才支持它。因此,Servlet应该通过查看Accept-Encoding头(即request.getHeader("Accept-Encoding"))检查浏览器是否支持gzip,为支持gzip的浏览器返回经gzip压缩的HTML页面,为其他浏览器返回普通页面。 | | Content-Length | 表示内容长度。只有当浏览器使用持久HTTP连接时才需要这个数据。如果你想要利用持久连接的优势,可以把输出文档写入 ByteArrayOutputStream,完成后查看其大小,然后把该值放入Content-Length头,最后通过byteArrayStream.writeTo(response.getOutputStream()发送内容。 | | Content-Type | 表示后面的文档属于什么MIME类型。Servlet默认为text/plain,但通常需要显式地指定为text/html。由于经常要设置Content-Type,因此HttpServletResponse提供了一个专用的方法setContentType。 | | Date | 当前的GMT时间。你可以用setDateHeader来设置这个头以避免转换时间格式的麻烦。 | | Expires | 应该在什么时候认为文档已经过期,从而不再缓存它? | | Last-Modified | 文档的最后改动时间。客户可以通过If-Modified-Since请求头提供一个日期,该请求将被视为一个条件GET,只有改动时间迟于指定时间的文档才会返回,否则返回一个304(Not Modified)状态。Last-Modified也可用setDateHeader方法来设置。 | | Location | 表示客户应当到哪里去提取文档。Location通常不是直接设置的,而是通过HttpServletResponse的sendRedirect方法,该方法同时设置状态代码为302。 | | Refresh | 表示浏览器应该在多少时间之后刷新文档,以秒计。除了刷新当前文档之外,你还可以通过setHeader("Refresh", "5; URL=http://host/path")让浏览器读取指定的页面。 注意这种功能通常是通过设置HTML页面HEAD区的<META HTTP-EQUIV="Refresh" CONTENT="5;URL=http://host/path">实现,这是因为,自动刷新或重定向对于那些不能使用CGI或Servlet的HTML编写者十分重要。但是,对于Servlet来说,直接设置Refresh头更加方便。 注意Refresh的意义是"N秒之后刷新本页面或访问指定页面",而不是"每隔N秒刷新本页面或访问指定页面"。因此,连续刷新要求每次都发送一个Refresh头,而发送204状态代码则可以阻止浏览器继续刷新,不管是使用Refresh头还是<META HTTP-EQUIV="Refresh" ...>。 注意Refresh头不属于HTTP 1.1正式规范的一部分,而是一个扩展,但Netscape和IE都支持它。 | | Server | 服务器名字。Servlet一般不设置这个值,而是由Web服务器自己设置。 | | Set-Cookie | 设置和页面关联的Cookie。Servlet不应使用response.setHeader("Set-Cookie", ...),而是应使用HttpServletResponse提供的专用方法addCookie。参见下文有关Cookie设置的讨论。 | | WWW-Authenticate | 客户应该在Authorization头中提供什么类型的授权信息?在包含401(Unauthorized)状态行的应答中这个头是必需的。例如,response.setHeader("WWW-Authenticate", "BASIC realm=\"executives\"")。 注意Servlet一般不进行这方面的处理,而是让Web服务器的专门机制来控制受密码保护页面的访问(例如.htaccess)。 | ### 7、HTTP 状态码 当浏览者访问一个网页时,浏览者的浏览器会向网页所在服务器发出请求。当浏览器接收并显示网页前,此网页所在的服务器会返回一个包含HTTP状态码的信息头(server header)用以响应浏览器的请求。 HTTP状态码的英文为HTTP Status Code。 **下面是常见的HTTP状态码:** - 200 - 请求成功 - 301 - 资源(网页等)被永久转移到其它URL 永久重定向 - 404 - 请求的资源(网页等)不存在 - 500 - 内部服务器错误 - 403 - 访问被拒绝 - 302 - 临时重定向 - 304 - 缓存 **HTTP状态码分类** HTTP状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型,后两个数字没有分类的作用。HTTP状态码共分为5种类型: ![1561896413177](assets/1561896413177.png) ###### HTTP状态码列表 | 状态码 | 状态码英文名称 | 中文描述 | | ------ | ------------------------------- | ------------------------------------------------------------ | | 100 | Continue | 继续。客户端应继续其请求 | | 101 | Switching Protocols | 切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到HTTP的新版本协议 | | | | | | 200 | OK | 请求成功。一般用于GET与POST请求 | | 201 | Created | 已创建。成功请求并创建了新的资源 | | 202 | Accepted | 已接受。已经接受请求,但未处理完成 | | 203 | Non-Authoritative Information | 非授权信息。请求成功。但返回的meta信息不在原始的服务器,而是一个副本 | | 204 | No Content | 无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档 | | 205 | Reset Content | 重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域 | | 206 | Partial Content | 部分内容。服务器成功处理了部分GET请求 | | | | | | 300 | Multiple Choices | 多种选择。请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择 | | 301 | Moved Permanently | 永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替 | | 302 | Found | 临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI | | 303 | See Other | 查看其它地址。与301类似。使用GET和POST请求查看 | | 304 | Not Modified | 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源 | | 305 | Use Proxy | 使用代理。所请求的资源必须通过代理访问 | | 306 | Unused | 已经被废弃的HTTP状态码 | | 307 | Temporary Redirect | 临时重定向。与302类似。使用GET请求重定向 | | | | | | 400 | Bad Request | 客户端请求的语法错误,服务器无法理解 | | 401 | Unauthorized | 请求要求用户的身份认证 | | 402 | Payment Required | 保留,将来使用 | | 403 | Forbidden | 服务器理解请求客户端的请求,但是拒绝执行此请求 | | 404 | Not Found | 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面 | | 405 | Method Not Allowed | 客户端请求中的方法被禁止 | | 406 | Not Acceptable | 服务器无法根据客户端请求的内容特性完成请求 | | 407 | Proxy Authentication Required | 请求要求代理的身份认证,与401类似,但请求者应当使用代理进行授权 | | 408 | Request Time-out | 服务器等待客户端发送的请求时间过长,超时 | | 409 | Conflict | 服务器完成客户端的PUT请求是可能返回此代码,服务器处理请求时发生了冲突 | | 410 | Gone | 客户端请求的资源已经不存在。410不同于404,如果资源以前有现在被永久删除了可使用410代码,网站设计人员可通过301代码指定资源的新位置 | | 411 | Length Required | 服务器无法处理客户端发送的不带Content-Length的请求信息 | | 412 | Precondition Failed | 客户端请求信息的先决条件错误 | | 413 | Request Entity Too Large | 由于请求的实体过大,服务器无法处理,因此拒绝请求。为防止客户端的连续请求,服务器可能会关闭连接。如果只是服务器暂时无法处理,则会包含一个Retry-After的响应信息 | | 414 | Request-URI Too Large | 请求的URI过长(URI通常为网址),服务器无法处理 | | 415 | Unsupported Media Type | 服务器无法处理请求附带的媒体格式 | | 416 | Requested range not satisfiable | 客户端请求的范围无效 | | 417 | Expectation Failed | 服务器无法满足Expect的请求头信息 | | | | | | 500 | Internal Server Error | 服务器内部错误,无法完成请求 | | 501 | Not Implemented | 服务器不支持请求的功能,无法完成请求 | | 502 | Bad Gateway | 作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应 | | 503 | Service Unavailable | 由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中 | | 504 | Gateway Time-out | 充当网关或代理的服务器,未及时从远端服务器获取请求 | | 505 | HTTP Version not supported | 服务器不支持请求的HTTP协议的版本,无法完成处理 | ## 二、Nginx入门 ### Nginx 介绍 Nginx (engine x) 是一个轻量级,高性能的 HTTP 和 反向代理服务,也是一个邮件代理服务,使用C编写。因它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名。其特点是占有内存少,并发能力强。 单机环境下并发连接数在7000+ -8000左右,集群模式20000+ 中国大陆使用nginx网站用户有:百度、[京东](https://baike.baidu.com/item/%E4%BA%AC%E4%B8%9C/210931)、[新浪](https://baike.baidu.com/item/%E6%96%B0%E6%B5%AA/125692)、[网易](https://baike.baidu.com/item/%E7%BD%91%E6%98%93/185754)、[腾讯](https://baike.baidu.com/item/%E8%85%BE%E8%AE%AF/112204)、[淘宝](https://baike.baidu.com/item/%E6%B7%98%E5%AE%9D/145661)等。 IIS 套件 windows apache netcraft.com 创始人伊戈尔·赛索耶夫 ![1561897072438](assets/1561897072438.png) ### 为什么选择 nginx ```bash 1.高并发,高性能 2.高可靠---可以7*24小时不间断运行 3.可扩展性强--模块化设计,使得添加模块非常的平稳。 4.热部署--可以在不停止服务器的情况下升级nginx 5.BSD许可证--nginx不止开源免费的我们还可以更具实际需求进行定制修改源代码 ``` **Nginx 安装非常的简单,配置文件非常简洁,Bugs非常少的服务器**: Nginx 启动特别容易,并且几乎可以做到**7*24**不间断运行,即使运行数个月也不需要重新启动。还能够在不间断服务的情况下进行软件版本的升级。 **作为 Web 服务器**:相比 Apache,Nginx 使用更少的资源,支持更多的并发连接,能够支持高达 50,000 个并发连接数的响应。 **作为负载均衡服务器**:可以进行自定义配置,支持虚拟主机,支持URL重定向,支持网络监控,支持流媒体传输等。 **作为邮件代理服务器**: Nginx 同时也是一个非常优秀的邮件代理服务器(最早开发这个产品的目的之一也是作为邮件代理服务器)。 ### IO多路复用 #### 1、I/O multiplexing(多并发) **传统的多进程并发模型** 每进来一个新的I/O流会分配一个新的线程管理。 ![1561897144109](assets/1561897144109.png) **I/O多路复用** 单个线程,通过记录跟踪每个I/O流(sock)的状态,来同时管理多个I/O流 。 ```bash I/O multiplexing 这里面的 multiplexing 指的其实是在单个线程通过记录跟踪每一个Sock(I/O流)的状态来同时管理多个I/O流。发明它的原因,是尽量多的提高服务器的吞吐能力。在同一个线程里面, 通过拨开关的方式,来同时传输多个I/O流 ``` ![1561897166658](assets/1561897166658.png) #### 2、Nginx实现I/O多路复用的方式 Nginx基于事件驱动模型实现I/O多路复用 **select, poll, epoll**都是I/O多路复用的具体的实现,他们的出现是有先后顺序的。 I/O多路复用这个概念被提出来以后, 相继出现了多个方案,但是都需要linux内核支持 select是第一个实现 (1983 左右实现的)。 select 被实现以后,很快就暴露出了很多问题。 ```bash select 任何一个sock(I/O stream)出现了数据,select 仅仅会返回,但是并不会告诉你是那个sock上有数据,于是你只能自己一个一个的找,10几个sock可能还好,要是几万的sock每次都找一遍... select 只能监视1024个链接。 select 线程不是安全的。 ``` 于是14年以后(1997年)一帮人又实现了**poll,** poll 修复了select的很多问题,比如 ```bash poll 去掉了1024个链接的限制,于是可以有多个连接进来。 但是poll仍然线程不是安全的, 这就意味着,不管服务器有多强悍,也只能在一个线程里面处理一组I/O流。 ``` epoll 是I/O 多路复用最新的一个实现,epoll 修复了poll 和select绝大部分问题, 比如: ```bash epoll 现在是线程安全的。 epoll 现在不仅告诉你sock组里面数据,还会告诉你具体哪个sock有数据,你不用自己去找了。 ngnix 会有很多连接进来, 默认采用epoll会把他们都监视起来,然后像拨开关一样,谁有数据就拨向谁,然后调用相应的代码处理。 ``` #### 3、异步非阻塞 ```bash # pstree |grep nginx |-+= 81666 root nginx: master process nginx \--- 82500 nobody nginx: worker process \--- 82501 nobody nginx: worker process ``` 1个master进程,n个work进程 每进来一个request,会有一个worker进程去处理。但不是全程的处理,处理到什么程度呢?处理到可能发生阻塞的地方,比如向上游(后端)服务器转发request,并等待请求返回。那么,这个处理的worker不会这么一直等着,他会在发送完请求后,注册一个事件:“如果upstream返回了,告诉我一声,我再接着干”。于是他就休息去了。这就是异步。此时,如果再有request进来,他就可以很快再按这种方式处理。这就是非阻塞和IO多路复用。而一旦上游服务器返回了,就会触发这个事件,worker才会来接手,这个request才会接着往下走。这就是异步回调。 ### Nginx vs Apache 内核和功能上的比较 | 特性 | Nginx | Apache | | :------- | :-------------------------------------------------------- | :----------------------------------------------------------- | | 请求管理 | 事件驱动模型,使用异步套接字处理,占用较少的内存和CPU开销 | 同步套接字、进程和线程每个请求都要使用一个单独的进程或线程,使用同步套接字 | | 设计语言 | C | C、C++ | | 可移植性 | 多平台 | 多平台 | | 诞生时间 | 2002 | 1994 | 一般功能比较 | 功能 | Nginx | Apache | | --------- | ------------- | ---------------- | | HTTPS支持 | 作为模块支持 | 作为模块支持 | | 虚拟主机 | 原生支持 | 原生支持 | | CGI支持 | 仅支持FastCGI | 支持CGI和FastCGI | | 系统模块 | 静态模块系统 | 动态模块系统 | ```bash FastCGI 快速通用网关接口(Fast Common Gateway Interface/FastCGI)是通用网关接口(CGI)的改进,描述了客户端和服务器程序之间传输数据的一种标准。FastCGI致力于减少Web服务器与CGI程序之间互动的开销,从而使服务器可以同时处理更多的Web请求。与为每个请求创建一个新的进程不同,FastCGI使用持续的进程来处理一连串的请求。这些进程由FastCGI进程管理器管理,而不是web服务器。 ``` 从以上功能上的对比,我们很难发现哪些功能Apache无法实现。那我们为什么更喜欢用Nginx 呢,Nginx 相对Apache 有那些有优点呢? ```bash - 轻量级,同样是web服务比Apache占用更少的内存及资源 - 静态处理,Nginx 静态处理性能比 Apache 高 3倍以上 - 抗并发,Nginx 处理请求是异步非阻塞的,而Apache则是阻塞型的。在高并发下Nginx能保持低资源低消耗高性能。 - 高度模块化的设计,编写模块相对简单 ``` 1. 并发量 apache 200 - 2000 nginx 50000 20000 8000 100000/86400 2. 稳定性 3. 功能 ### Nginx安装 #### 1、Yum方式安装 nginx的官方网站: Nginx现在属于f5 f5做硬件负载均衡器 **Nginx版本** ```bash Mainline version 主线版 Stable version 最新稳定版,生产环境上建议使用的版本 Legacy versions 遗留的老版本的稳定版 ``` **配置Yum源** 官方download页面 ![image-20220613141023470](assets/image-20220613141023470.png) Install the prerequisites: > ```bash > # yum install yum-utils -y > ``` To set up the yum repository, create the file named `/etc/yum.repos.d/nginx.repo` with the following contents: > ```bash > [nginx-stable] > name=nginx stable repo > baseurl=http://nginx.org/packages/centos/$releasever/$basearch/ > gpgcheck=1 > enabled=1 > gpgkey=https://nginx.org/keys/nginx_signing.key > module_hotfixes=true > > [nginx-mainline] > name=nginx mainline repo > baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/ > gpgcheck=1 > enabled=0 > gpgkey=https://nginx.org/keys/nginx_signing.key > module_hotfixes=true > ``` By default, the repository for stable nginx packages is used. If you would like to use mainline nginx packages, run the following command: > ```bash > # yum-config-manager --enable nginx-mainline > ``` To install nginx, run the following command: > ```bash > # yum install nginx -y > ``` 查看详细安装信息 ```bash # nginx -V # nginx -v -V 查看详细安装信息 -v 单独查看版本信息 ``` 启动并设置开机启动 ```bash 注意防火墙和selinux # systemctl start nginx # systemctl enable nginx ``` 浏览器测试访问 ```http http://localhost ``` #### 2、编译方式安装 安装编译环境 ```bash # yum -y install gcc gcc-c++ pcre pcre-devel gd-devel openssl-devel zlib zlib-devel pcre使nginx支持http rewrite模块 openssl 使nginx支持ssl zlib提供nginx对http包的内容进行gzip压缩 ``` 创建用户nginx ```bash # useradd nginx ``` 下载安装Nginx ![image-20220613145148325](assets/image-20220613145148325.png) 查询下载链接 ```bash # wget http://nginx.org/download/nginx-1.22.0.tar.gz # tar xzf nginx-1.22.0.tar.gz -C /usr/local/ # cd /usr/local/nginx-1.22.0/ # ./configure --prefix=/usr/local/nginx --group=nginx --user=nginx --sbin-path=/usr/local/nginx/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/tmp/nginx/client_body --http-proxy-temp-path=/tmp/nginx/proxy --http-fastcgi-temp-path=/tmp/nginx/fastcgi --pid-path=/var/run/nginx.pid --lock-path=/var/lock/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_gzip_static_module --with-pcre --with-http_realip_module --with-stream # make && make install ``` Nginx 编译参数 ```bash # 查看 nginx 安装的模块 #/usr/local/nginx/sbin/nginx -V --prefix=/usr/local/nginx //指向安装目录 --conf-path=/etc/nginx/nginx.conf //指定配置文件 --http-log-path=/var/log/nginx/access.log //指定访问日志 --error-log-path=/var/log/nginx/error.log //指定错误日志 --lock-path=/var/lock/nginx.lock //指定lock文件 --pid-path=/run/nginx.pid //指定pid文件 --http-client-body-temp-path=/var/lib/nginx/body //设定http客户端请求临时文件路径 --http-fastcgi-temp-path=/var/lib/nginx/fastcgi //设定http fastcgi临时文件路径 --http-proxy-temp-path=/var/lib/nginx/proxy //设定http代理临时文件路径 --http-scgi-temp-path=/var/lib/nginx/scgi //设定http scgi临时文件路径 --http-uwsgi-temp-path=/var/lib/nginx/uwsgi //设定http uwsgi临时文件路径 --with-debug //启用debug日志 --with-ipv6 //启用ipv6支持 --with-http_ssl_module //启用ssl支持 --with-http_stub_status_module //获取nginx自上次启动以来的状态 --with-http_realip_module //允许从请求标头更改客户端的IP地址值,默认为关 --with-http_auth_request_module //实现基于一个子请求的结果的客户端授权。如果该子请求返回的2xx响应代码,所述接入是允许的。如果它返回401或403中,访问被拒绝与相应的错误代码。由子请求返回的任何其他响应代码被认为是一个错误。 --with-http_addition_module //作为一个输出过滤器,支持不完全缓冲,分部分响应请求 --with-http_dav_module //增加PUT,DELETE,MKCOL:创建集合,COPY和MOVE方法 默认关闭,需编译开启 --with-http_geoip_module //使用预编译的MaxMind数据库解析客户端IP地址,得到变量值 --with-http_gunzip_module //它为不支持“gzip”编码方法的客户端解压具有“Content-Encoding: gzip”头的响应。 --with-http_gzip_static_module //在线实时压缩输出数据流 --with-http_spdy_module //SPDY可以缩短网页的加载时间 --with-http_sub_module //允许用一些其他文本替换nginx响应中的一些文本 --with-http_xslt_module //过滤转换XML请求 --with-mail //启用POP3/IMAP4/SMTP代理模块支持 --with-mail_ssl_module //启用ngx_mail_ssl_module支持启用外部模块支持 #--with 表示在编译过程中需要给nginx添加的模块 #--without 表示编译nginx时默认该模块是添加进去的当使用这个参数时表示将默认编译的模块移除 ``` **修改配置文件** **nginx.conf的组成** nginx.conf一共由三部分组成,分别为:全局块、events块、http块。 在http块中又包含http全局块、多个server块。 每个server块中又包含server全局块以及多个location块。 ```bash # vim /etc/nginx/nginx.conf # 全局参数设置 user nginx; worker_processes 4; #设置nginx启动进程的数量,一般设置成与逻辑cpu数量相同 error_log logs/error.log; pid /var/run/nginx.pid; events { worker_connections 1024; #设置一个进程的最大并发连接数 } # http 服务相关设置 http { include mime.types; #关联资源的媒体类型 default_type application/octet-stream; #根据文件的后缀来匹配相应的MIME类型 log_format main 'remote_addr - remote_user [time_local] "request" ' 'status body_bytes_sent "$http_referer" ' '"http_user_agent" "http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #用于开启文件高效传输模式,一般设置为on,若nginx是用来进行磁盘IO负载应用时,可以设置为off,降低系统负载 tcp_nopush on; # 减少网络报文段数量,当有数据时,先别着急发送, 确保数据包已经装满数据, 避免了网络拥塞 tcp_nodelay on; # 提高I/O性能,确保数据尽快发送, 提高可数据传输效率 gzip on; #是否开启gzip压缩 keepalive_timeout 65; #设置长连接的超时时间,请求完成之后还要保持连接多久, # 虚拟服务器的相关设置 server { listen 80; server_name localhost; #设置绑定的主机名、域名或ip地址 charset koi8-r; # 设置编码字符 location / { root /var/www/nginx; #设置服务器默认网站的根目录位置,需要手动创建 index index.html index.htm; #设置默认打开的文档 } error_page 500 502 503 504 /50x.html; #设置错误信息返回页面 location = /50x.html { root html; #这里的绝对位置是/usr/local/nginx/html } } } ``` 检测Nginx配置文件语法 ```shell # mkdir -p /tmp/nginx //创建临时测试数据目录 # /usr/local/nginx/sbin/nginx -t ``` Nginx 服务管理 ```bash # /usr/local/nginx/sbin/nginx //启动服务 # nginx -c /path/nginx.conf # 以特定目录下的配置文件启动nginx: # nginx -s reload # 修改配置后重新加载生效 # nginx -s stop # 快速停止nginx # nginx -s quit # 正常停止nginx # nginx -t # 测试当前配置文件是否正确 # nginx -t -c /path/to/nginx.conf # 测试特定的nginx配置文件是否正确 #注意 nginx -s reload 命令加载修改后的配置文件,命令下达后发生如下事件 1. Nginx的master进程检查配置文件的正确性,若是错误则返回错误信息,nginx继续采用原配置文件进行工作(因为worker未受到影响) 2. Nginx启动新的worker进程,采用新的配置文件 3. Nginx将新的请求分配新的worker进程 4. Nginx等待以前的worker进程的全部请求已经都返回后,关闭相关worker进程 5. 重复上面过程,知道全部旧的worker进程都被关闭掉 ``` ### Nginx 虚拟主机 服务器配置比较高 访问量不大 可以用一个nginx提供多个网站服务 每一个网站都是一个虚拟主机 虚拟机 虚拟主机 提供一个独立的网站 客户端连接的时候服务器看起来像一台主机,实际不是 ​ 紧紧是web服务器提供的一个能发布网站的目录 ​ 每个web服务器可以同时发布多个网站,每个网站都是一个虚拟主机,在服务器上是目录形式存在 云主机 vps(虚拟专用服务器) 虚拟机 vps 云主机 虚拟主机 nginx apache 配置的一个能发布网站的环境 虚拟主机是一种特殊的软硬件技术,它可以将网络上的每一台计算机分成多个虚拟主机,每个虚拟主机可以独立对外提供www服务,这样就可以实现一台主机对外提供多个web服务,每个虚拟主机之间是独立的,互不影响。 ![1561605672295](assets/1561605672295.png) Nginx支持三种类型的虚拟主机 ```bash 1、基于域名的虚拟主机 (server_name来区分虚拟主机——应用:外部网站) 2、基于ip的虚拟主机, (一块主机绑定多个ip地址) 3、基于端口的虚拟主机 (端口来区分虚拟主机——应用:公司内部网站,外部网站的管理后台) ``` #### 基于域名的虚拟主机 1、配置通过域名区分的虚拟机 ```bash # cat /etc/nginx/nginx.conf worker_processes 4; #error_log logs/error.log; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; server { listen 80; server_name web.testpm.com; location / { root /var/www/nginx/; index index.html index.htm; limit_rate 2k; } } server { listen 80; server_name www.1000phone.com; location / { root /1000phone/html; index index.html index.htm; } } } ``` 2、 为域名为 web.1000phone.com 的虚拟机,创建 index 文件 ```bash [root@localhost ~]# mkdir -p /1000phone/html [root@localhost ~]# vim /1000phone/html/index.html

this is my 1000phone

``` 3、重新加载配置文件 ```bash # /usr/local/nginx/sbin/nginx -s reload ``` 4、客户端配置路由映射 ```bash 在 C:\Windows\System32\drivers\etc\hosts 文件中添加两行(linux:/etc/hosts) ``` ```bash 10.0.105.199 web.testpm.com 10.0.105.199 web.1000phone.com ``` 5、 测试访问 ```bash 浏览器输入:http://web.testpm.com/ 浏览器输入:http://web.1000phone.com/ ``` #### 基于ip的虚拟主机 ```bash [root@localhost ~]# ip a 1: lo: mtu 65536 qdisc noqueue state UNKNOWN qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: ens33: mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 00:0c:29:17:f1:af brd ff:ff:ff:ff:ff:ff inet 10.0.105.199/24 brd 10.0.105.255 scope global dynamic ens33 valid_lft 81438sec preferred_lft 81438sec inet6 fe80::9d26:f3f0:db9c:c9be/64 scope link valid_lft forever preferred_lft forever [root@localhost ~]# ifconfig ens33:1 10.0.105.201/24 [root@localhost ~]# ifconfig ens33: flags=4163 mtu 1500 inet 10.0.105.199 netmask 255.255.255.0 broadcast 10.0.105.255 inet6 fe80::9d26:f3f0:db9c:c9be prefixlen 64 scopeid 0x20 ether 00:0c:29:17:f1:af txqueuelen 1000 (Ethernet) RX packets 9844 bytes 1052722 (1.0 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 5567 bytes 886269 (865.4 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 ens33:1: flags=4163 mtu 1500 inet 10.0.105.201 netmask 255.255.255.0 broadcast 10.0.105.255 ether 00:0c:29:17:f1:af txqueuelen 1000 (Ethernet) 2、配置通过ip区分的虚拟机 # cat /etc/nginx/nginx.conf user root; worker_processes 4; #error_log logs/error.log; 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"'; server { listen 10.0.105.199:80; server_name web.testpm.com; location / { root /var/www/nginx/; index index.html index.htm; limit_rate 2k; } server { listen 10.0.105.201:80; server_name www.testpm.com; location / { root /1000phone/html/; index index.html index.htm; } } } 3、重新加载配置文件 # /usr/local/nginx/sbin/nginx -s reload 4、 测试访问 浏览器输入:http://10.0.105.199 浏览器输入:http://10.0.105.201 5、补充 -- 删除绑定的vip [root@localhost ~]# ifconfig ens33:1 10.0.105.201/24 down 重启一下nginx [root@localhost ~]# systemctl restart nginx ``` #### 基于端口的虚拟主机 ```bash # cat /etc/nginx/nginx.conf user root; worker_processes 4; 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"'; sendfile on; keepalive_timeout 65; server { listen 80; server_name web.testpm.com; location / { root /var/www/nginx/; index index.html index.htm; limit_rate 2k; } server { listen 8080; server_name www.testpm.com; location / { root /1000phone/html/; index index.html index.htm; } } } 重新加载配置文件: # /usr/local/nginx/sbin/nginx -s reload 测试访问: 浏览器输入:http://web.testpm.com/ 浏览器输入:http://web.1000phone.com:8080 ``` ## 三、Nginx进阶 ### Nginx 日志 `Nginx` 有一个非常灵活的日志记录模式,每个级别的配置可以有各自独立的访问日志, 所需日志模块为 `ngx_http_log_module` ,日志格式通过 `log_format` 命令来定义,日志对于统计和排错是非常有利的.`nginx` 日志相关的配置包括 `access_log`、`log_format`、`rewrite_log`、`error_log`。 #### **access_log指令** 作用域 ​ 可以应用`access_log`指令的作用域分别有`http`,`server`,`location`,也就是说,在这几个作用域外使用该指令,Nginx会报错。 ```shell # 设置访问日志 access_log path; //path指定日志的存放位置。 # 关闭访问日志 access_log off; ``` ```shell access_log /var/logs/nginx-access.log ``` 该例子指定日志的写入路径为`/var/logs/nginx-access.log`,日志格式使用默认的`main`。 #### **log-format指令** Nginx 预定义了名为 "main"的日志格式,如果没有明确指定日志格式默认使用该格式: ```bash log_format main 'remote_addr - remote_user [time_local] "request" ' 'status body_bytes_sent "$http_referer" ' '"http_user_agent" "http_x_forwarded_for"'; ``` ![1561599608585](assets/1561599608585.png) ![1561599718230](assets/1561599718230.png) 如果不想使用Nginx预定义的格式,可以通过`log_format`指令来自定义。 语法 ```shell log_format name [escape=default|json] string ...; ``` ```bash - name 格式名称。在 access_log 指令中引用。 - escape 设置变量中的字符编码方式是`json`还是`default`,默认是`default`。 - string 要定义的日志格式内容。该参数可以有多个。参数中可以使用Nginx变量。 ``` `log_format` 指令中常用的一些变量: ```shell $remote_addr, $http_x_forwarded_for #记录客户端IP地址 $remote_user #记录客户端用户名称 $request #记录请求的URL和HTTP协议 $status #记录请求状态 $body_bytes_sent #发送给客户端的字节数,不包括响应头的大小 $bytes_sent #发送给客户端的总字节数 $connection #连接的序列号 $connection_requests #当前通过一个连接获得的请求数量。 $msec #日志写入时间。单位为秒,精度是毫秒。 $http_referer #记录从哪个页面链接访问过来的,可以根据该参数进行防盗链设置 $http_user_agent #记录客户端浏览器相关信息 $request_length #请求的长度(包括请求行,请求头和请求正文)。 $request_time #请求处理时间,单位为秒,精度毫秒; 从读入客户端的第一个字节开始,直到把最后一个字符发送给客户端后进行日志写入为止。 $time_iso8601 #ISO8601标准格式下的本地时间。 $time_local #通用日志格式下的本地时间。 ``` 自定义日志格式的使用: ```shell access_log /var/logs/nginx-access.log main log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; ``` ```shell 注意: 如果Nginx位于负载均衡器,nginx反向代理之后,web服务器无法直接获取到客户端真实的IP地址。 $remote_addr获取的是反向代理的IP地址。反向代理服务器在转发请求的http头信息中,可以增加X-Forwarded-For信息,用来记录客户端IP地址。 ``` 使用`log_format`指令定义了一个`main`的格式,并在`access_log`指令中引用了它。客户端发起请求访问:`http://192.168.246.154/`,看一下请求的日志记录: ```shell 10.0.105.207 - - [01/Jul/2019:10:44:36 +0800] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36" "-" ``` 我们看到最终的日志记录中`$remote_user`、`$http_referer`、`$http_x_forwarded_for`都对应了一个`-`,这是因为这几个变量为空。 **面试时注意:日志里面的ip地址一定在第一列。** #### **error_log 指令** 错误日志在Nginx中是通过`error_log`指令实现的。该指令记录服务器和请求处理过程中的错误信息。 **语法** 配置错误日志文件的路径和日志级别。 ```shell error_log file [level]; Default: error_log logs/error.log error; ``` `file` 参数指定日志的写入位置。 `level` 参数指定日志的级别。level可以是`debug`, `info`, `notice`, `warn`, `error`, `crit`, `alert`,`emerg`中的任意值。可以看到其取值范围是按紧急程度从低到高排列的。只有日志的错误级别等于或高于level指定的值才会写入错误日志中。默认值是`error`。 ```shell 日志级别 debug:低级别,包含的信息非常详细 info:稍微的高一点了。用的多一些。 notice:相当于提示 warning:警告 和warn 一样 err和error 一样。 crit:比较严重了 alert:告警,很严重 emerg: 恐慌级别, 级别最高的 ``` **基本用法** ```shell error_log /var/logs/nginx/nginx-error.log emerg; ``` 配置段: `http`, `server`, `location`作用域。 例子中指定了错误日志的路径为:`/var/logs/nginx/nginx-error.log`,日志级别使用默认的 `error`。 #### **rewrite_log 指令** 由`ngx_http_rewrite_module`模块提供的。用来记录重写日志的。对于调试重写规则建议开启,启用时将在`error log`中记录`notice`级别的重写日志。 **基本语法:** ```shell rewrite_log on | off; 默认值: rewrite_log off; ``` 配置段: `http`, `server`, `location`, `if`作用域。 **nginx 日志配置总结** Nginx中通过`access_log`和`error_log`指令配置访问日志和错误日志,通过`log_format`我们可以自定义日志格式。 详细的日志配置信息可以参考[Nginx官方文档](https://link.juejin.im/?target=http%3A%2F%2Fnginx.org%2Fen%2Fdocs%2Fvarindex.html) **单独开启server的访问日志** ```shell [root@nginx-client ~]# cd /etc/nginx/conf.d/ [root@nginx-client conf.d]# vim nginx.conf server { listen 80; server_name localhost; charset koi8-r; access_log /var/log/nginx/test.access.log main; location / { root /usr/share/nginx/html; index index.html index.htm; } location /admin { root /usr/share/nginx/html; index index.html index.htm; } } # nginx -s reload 访问 # curl -I http://192.168.1.10 ``` ![1567612056482](assets/1567612056482.png) 当我们访问的这个server的时候日志将会输出到test.access.log. ![1567612351854](assets/1567612351854.png) #### Nginx日志轮转 ```shell [root@192 ~]# rpm -ql nginx |grep log /etc/logrotate.d/nginx /var/log/nginx [root@192 ~]# vim /etc/logrotate.d/nginx /var/log/nginx/*.log { #指定需要轮转处理的日志文件 daily #日志文件轮转周期,可用值为: daily/weekly/yearly missingok #忽略错误信息 rotate 7 #轮转次数,即最多存储7个归档日志,会删除最久的归档日志 minsize 5M #限制条件,大于5M的日志文件才进行分割,否则不操作 dateext #以当前日期作为命名格式 compress #轮循结束后,已归档日志使用gzip进行压缩 delaycompress #与compress共用,最近的一次归档不要压缩 notifempty # 日志文件为空,轮循不会继续执行 create 640 nginx nginx #新日志文件的权限 sharedscripts #有多个日志需要轮询时,只执行一次脚本 postrotate #将日志文件转储后执行的命令。以endscript结尾,命令需要单独成行 if [ -f /var/run/nginx.pid ]; then #判断nginx的PID。默认logrotate会以root身份运行 kill -USR1 cat /var/run/nginx.pid fi endscript } 执行命令: # /usr/sbin/logrotate -f /etc/logrotate.conf 创建计划任务: # crontab -e 59 23 * * * /usr/sbin/logrotate -f /etc/logrotate.conf ``` ### Nginx Proxy 反向代理 ![1561616855038](assets/1561616855038.png) #### 正向代理 **正向代理的过程隐藏了真实的请求客户端,服务器不知道真实的客户端是谁,客户端请求的服务都被代理服务器代替请求。**我们常说的代理也就是正向代理,正向代理代理的是请求方,也就是客户端;比如我们要访问youtube,可是不能访问,只能先安装个FQ软件代你去访问,通过FQ软件才能访问,FQ软件就叫作正向代理。 ![image-20200907163034923](assets/image-20200907163034923.png) #### 反向代理 **反向代理的过程隐藏了真实的服务器,客户不知道真正提供服务的是谁,客户端请求的服务都被代理服务器处理。反向代理代理的是响应方,也就是服务端;**我们请求www.baidu.com时,这www.baidu.com就是反向代理服务器,真实提供服务的服务器有很多台,反向代理服务器会把我们的请求分转发到真实提供服务的各台服务器。Nginx就是性能非常好的反向代理服务器 ![1561617154985](assets/1561617154985.png) ![image-20200907163302135](assets/image-20200907163302135.png) 两者的区别在于代理的对象不一样 ```bash 正向代理中代理的对象是客户端。 反向代理中代理的对象是服务端。 ``` 知识扩展:HTTP Server和Application Server的区别和联系 ```bash HTTP Server(Nginx/Apache)常用做静态内容服务和代理服务器,将外来请求转发给后面的应用服务(tomcat,jboss,php等)。 应用服务器(tomcat/jboss/php)是动态服务器(Application Server): ``` #### Nginx Proxy 配置 模块:ngx_http_proxy_module a、nginx-1 作为应用服务器,ip地址为:10.0.105.199 b、nginx-2 作为代理服务器,ip地址为:10.0.105.202 ```shell nginx-2的配置文件: # vim /etc/nginx/conf.d/default.conf http { server { listen 80; server_name localhost; location / { proxy_pass http://10.0.105.199:80; #nginx-1地址,真实后端服务器地址,可以是ip或域名 proxy_redirect default; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_connect_timeout 30; proxy_send_timeout 60; proxy_read_timeout 60; } } } ``` ```shell proxy_redirect :如果真实服务器使用的是的真实IP:非默认端口。则改成IP:默认端口。 proxy_set_header:重新定义或者添加发往后端服务器的请求头 在有多层代理的情况下通过下面两个选项可以记录真正客户端机器的ip地址 proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_connect_timeout:后端服务器连接的超时时间发起三次握手等候响应超时时间 proxy_send_timeout:后端服务器数据回传时间,就是在规定时间之内后端服务器必须传完所有的数据 proxy_read_timeout :nginx接收upstream(上游/真实) server数据超时, 默认60s, 如果连续的60s内没有收到1个字节, 则连接关闭。像长连接 ``` ```bash 使用PC客户端访问nginx-2服务器地址 浏览器中输入http://10.0.105.202,成功则访问到的是nginx-1服务器页面 ``` 观察nginx-1服务器的日志 ```shell 10.0.105.202 - - [27/Jun/2019:15:54:17 +0800] "GET / HTTP/1.0" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36" "10.0.105.207" ``` ```bash 10.0.105.202 代理服务器地址 10.0.105.207 客户机地址。 访问成功。 记录了客户机的IP和代理服务器的IP ``` #### **proxy_redirect解析** ```bash 环境: 代理服务ip:192.168.26.142 真实服务ip:192.168.26.143 代理服务器配置如下: server { listen 80; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; #location / { # root html; # index index.html index.htm; #} location / { proxy_pass http://192.168.26.143:8080; proxy_redirect off; } 问题描述: 1.端口为非默认80端口 2.被访问地址为子目录 3.客户端访问的URL地址最后没有加/ 客户端访问后则会出现如下响应头信息且访问出错 错误信息: # curl http://192.168.26.142/test 301 Moved Permanently

301 Moved Permanently


nginx/1.22.0
响应头信息: # curl -I http://192.168.26.142/test HTTP/1.1 301 Moved Permanently Server: nginx/1.22.0 Date: Mon, 13 Jun 2022 10:22:36 GMT Content-Type: text/html Content-Length: 169 Connection: keep-alive Location: http://192.168.26.143:8080/test/ ``` **问题所在:** 响应头信息带 http://192.168.26.143:8080/test/ **这里location为带有后端服务器实际地址跟端口的响应头信息这样在实际线上会暴露后端服务器的信息,所以是不允许的。** **解决:** 通过proxy_redirect将被代理服务器的响应头中的location字段进行修改后返回给客户端,**注意此配置不会解决错误**,但是错误响应头信息发生了变化,返回客户端的地址变成了http://192.168.26.142/test/ ```bash server { listen 80; server_name localhost; location / { proxy_pass http://192.168.26.143:8080; #proxy_redirect http://192.168.26.143:8080/test/ http://192.168.26.142/test/; proxy_redirect ~^ http://192.168.26.143:8080(.*) http://192.168.26.142$1; } ``` 结果如下: ``` # curl -I http://192.168.26.142/test HTTP/1.1 301 Moved Permanently Server: nginx/1.22.0 Date: Mon, 13 Jun 2022 10:44:00 GMT Content-Type: text/html Content-Length: 169 Connection: keep-alive Location: http://192.168.26.142/test/ ``` ### Nginx负载均衡 haproxy 专业负载均衡 lvs负载均衡和nginx负载均衡的区别 **upstream模块** upstream 配置的是一组被代理的服务器地址+负载均衡算法 ```shell upstream testapp { ip_hash; server 10.0.105.199:8081 weight=1; server 10.0.105.202:8081 weight=2; } server { .... location / { proxy_pass http://testapp; #请求转向 testapp 定义的服务器列表 } ``` **负载均衡算法** ```bash upstream支持4种负载均衡调度算法 1、轮询(默认):每个请求按时间顺序逐一分配到不同的后端服务器; 加权轮询 轮叫 2、ip_hash:每个请求按访问IP的hash结果分配,同一个IP客户端固定访问一个后端服务器。可以保证来自同一ip的请求被打到固定的机器上,可以解决session问题。 3、url_hash:按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器。 4、fair:这是比上面两个更加智能的负载均衡算法。此种算法可以依据页面大小和加载时间长短智能地进行负载均衡,也就是根据后端服务器的响应时间来分配请求,响应时间短的优先分配。Nginx本身是不支持 fair的,如果需要使用这种调度算法,必须下载Nginx的 upstream_fair模块。 ``` **配置实例** 1、热备:如果你有2台服务器,当一台服务器发生事故时,才启用第二台服务器给提供服务。服务器处理请求的顺序:AAAAAA突然A挂啦,BBBBBBBBBBBBBB..... ```shell upstream myweb { server 172.17.14.2:8080; server 172.17.14.3:8080 ; #热备 } ``` 2、轮询:nginx默认就是轮询其权重都默认为1,服务器处理请求的顺序:ABABABABAB.... ```shell upstream myweb { server 172.17.14.2:8080; server 172.17.14.3:8080; } ``` 3、加权轮询:跟据配置的权重的大小而分发给不同服务器不同数量的请求。如果不设置,则默认为1。下面服务器的请求顺序为:ABBABBABBABBABB.... ```shell upstream myweb { server 172.17.14.2:8080 weight=1; server 172.17.14.3:8080 weight=2; } ``` 4、ip_hash:nginx会让相同的客户端ip请求相同的服务器。 ```shell upstream myweb { server 172.17.14.2:8080; server 172.17.14.3:8080; ip_hash; } ``` 5、nginx负载均衡配置状态参数 ```bash - down,表示当前的server暂时不参与负载均衡。 - backup,预留的备份机器。当其他所有的非backup机器出现故障或者忙的时候,才会请求backup机器,因此这台机器的压力最轻。 - max_fails,允许请求失败的次数,默认为1。当超过最大次数时,返回proxy_next_upstream 模块定义的错误。 - fail_timeout,在经历了max_fails次失败后,暂停服务的时间单位秒。max_fails可以和fail_timeout一起使用。 ``` ```shell upstream myweb { server 172.17.14.2:8080 weight=2 max_fails=2 fail_timeout=2; server 172.17.14.3:8080 weight=1 max_fails=2 fail_timeout=1; } ``` ### 会话保持(sticky模块了解) Nginx会话保持主要有以下几种实现方式。 1、ip_hash ```bash ip_hash使用源地址哈希算法,将同一客户端的请求总是发往同一个后端服务器,除非该服务器不可用。 ip_hash语法: ``` ```shell upstream backend { ip_hash; server backend1.example.com; server backend2.example.com; server backend3.example.com down; } ``` ```bash ip_hash简单易用,但有如下问题: 当后端服务器宕机后,session会丢失; 来自同一局域网的客户端会被转发到同一个后端服务器,可能导致负载失衡; ``` 2、sticky_cookie_insert---是基于cookie实现 ```bash 使用sticky_cookie_insert,这会让来自同一客户端的请求被传递到一组服务器的同一台服务器。与ip_hash不同之处在于,它不是基于IP来判断客户端的,而是基于cookie来判断。(需要引入第三方模块才能实现)---sticky模块 ``` 语法: ```shell 编译安装sticky模块,#给yum安装的nginx添加模块 [root@nginx-server ~]# yum install -y pcre* openssl* gcc gcc-c++ make 安装编译环境 [root@nginx-server ~]# wget https://bitbucket.org/nginx-goodies/nginx-sticky-module-ng/get/08a395c66e42.zip #下载sticky模块 [root@nginx-server ~]# nginx -v nginx version: nginx/1.18.0 [root@nginx-server ~]# wget http://nginx.org/download/nginx-1.18.0.tar.gz #下载yum安装nginx对应版本的源码包 [root@nginx-server ~]# yum install -y unzip #安装解压工具 [root@nginx-server ~]# unzip 08a395c66e42.zip #解压模块包 [root@nginx-server ~]# mv nginx-goodies-nginx-sticky-module-ng-08a395c66e42/ nginx-sticky-module-ng/ [root@nginx-server ~]# tar xzvf nginx-1.18.0.tar.gz -C /usr/local/ #解压nginx的源码包 [root@nginx-server ~]# cd /usr/local/nginx-1.18.0/ [root@nginx-server nginx-1.18.0]# nginx -V #查看yum安装nginx所有模块 [root@nginx-server nginx-1.18.0]# ./configure --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie' --add-module=/root/nginx-sticky-module-ng [root@nginx-server nginx-1.18.0]# make && make install 配置基于cookie会话保持 [root@nginx-server conf.d]# vim upstream.conf upstream qfedu { server 192.168.198.143; server 192.168.198.145; sticky; } [root@nginx-server conf.d]# vim proxy.conf server { listen 80; server_name localhost; #charset koi8-r; #access_log /var/log/nginx/host.access.log main; location / { proxy_pass http://qfedu; } } [root@nginx-server conf.d]# nginx -t [root@nginx-server conf.d]# nginx -s reload 或者: upstream qfedu { server 192.168.198.143; server 192.168.198.145; sticky expires=1h domain=testpm.com path=/; } 说明: expires:设置浏览器中保持cookie的时间 domain:定义cookie的域 path:为cookie定义路径 ``` 浏览器测试访问 ### Nginx 实现动静分离 为了加快网站的解析速度,可以把动态页面和静态页面由不同的服务器来解析,加快解析速度。降低原来单个服务器的压力。 简单来说,就是使用正则表达式匹配过滤,然后交给不同的服务器。 **1、准备环境** 准备一个nginx代理 两个http 分别处理动态和静态。 ```ini expires功能说明---(为客户端配置缓存时间)   nginx缓存的设置可以提高网站性能,对于网站的图片,尤其是新闻网站,图片一旦发布,改动的可能是非常小的,为了减小对服务器请求的压力,提高用户浏览速度,我们可以通过设置nginx中的expires,让用户访问一次后,将图片缓存在用户的浏览器中,且时间比较长的缓存。 原理:当nginx设置了expires后,例如设置为:expires 10d; 那么用户在10天内请求的时候,都只会访问浏览器中的缓存,而不会去请求nginx。 需要注意的是,这种缓存方式只能在用户不对浏览器强制刷新的情况下生效,如果用户通过url来进行访问,是可以访问到缓存的。 ``` 1.静态资源配置 ```shell server { listen 80; server_name localhost; location ~ \.(html|jpg|png|js|css) { root /home/www/nginx; expires 1d; #为客户端设置静态资源缓存时间 } } 测试: [root@nginx-yum2 conf.d]# curl -I http://10.0.105.200/test.jpg HTTP/1.1 200 OK Server: nginx/1.16.0 Date: Mon, 07 Sep 2019 11:35:08 GMT Content-Type: image/jpeg Content-Length: 27961 Last-Modified: Mon, 07 Sep 2019 11:31:17 GMT Connection: keep-alive ETag: "5f561a05-6d39" Expires: Tue, 08 Sep 2019 11:35:08 GMT #缓存到期时间 Cache-Control: max-age=86400 #缓存持续时间秒 Accept-Ranges: bytes ``` 2.动态资源配置 **centos7步骤如下:** ```shell yum 安装php7.1 [root@nginx-server ~] # rpm -Uvh https://mirror.webtatic.com/yum/el7/epel-release.rpm [root@nginx-server ~] # rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm [root@nginx-server ~] # yum install php71w-xsl php71w php71w-ldap php71w-cli php71w-common php71w-devel php71w-gd php71w-pdo php71w-mysql php71w-mbstring php71w-bcmath php71w-mcrypt -y [root@nginx-server ~]# yum install -y php71w-fpm ``` **centos-stream 8因为软件比较新,无需使用第三方库,步骤如下:** ```bash # yum install php-cli php-fpm php-gd php-mysqlnd php-mbstring php-opcache php-pdo -y 只需要修改/etc/php-fpm.d/www.conf配置文件中的apache用户和组为nginx即可启动服务 # vim /etc/php-fpm.d/www.conf .... user = nginx #默认是apache group = nginx .... # systemctl start php-fpm # systemctl enable php-fpm ``` PHP-FPM(FastCGI Process Manager:FastCGI进程管理器)是一个PHP FastCGI管理器。它提供了更好的PHP进程管理方式,可以有效控制内存和进程、可以平滑重载PHP配置。在日常运维中,我们主要将PHP-FPM 的配置文件分为主配置文件和 pool配置文件(每个pool配置文件通常对应一个Nginx虚拟主机)。 1、PHP-FPM 主配置文件--主要是php的优化 **注意:本次安装不需要配置这些优化选项** ```ini 主配置文件 php-fpm.conf,常用配置如下: 设置php-fpm最大进程数 [root@nginx-yum2 ~]# vim /etc/php-fpm.conf [global] ... ;动态方式下开启的php-fpm进程的最大数量 process.max = 2048 ;设置 fpm 在后台运行 daemonize = yes ; 设置进程可以打开的文件描述符数量 rlimit_files = 65535 ; 设置FPM 的事件处理机制 events.mechanism = epoll ; 加载pool 配置 include = /etc/fpm.d/*.conf 设置进程池 [root@nginx-yum2 ~]# vim /etc/php-fpm.d/www.conf [www] ... ; 设置动态dynamic进程池/静态static pm = dynamic ; 设置每个进程可处理的请求数,当进程达到这个请求数量后会自动释放在重新生成新的进程。避免内存泄漏等情况 pm.max_requests = 1500 ; 终止请求超时时间。一个请求若处理大于20s ,则会自动kill掉。避免进程堆积 request_terminate_timeout = 20 ; 限制 FPM 允许解析的脚本扩展名. 这里不限制,FPM可以解析任何扩展名的文件 security.limit_extensions = "" 修改php上传文件的大小 [root@nginx-yum2 ~]# vim /etc/php.ini max_execution_time = 0 #默认的该脚本最久执行时间为30秒.就是说超过30秒,该脚本就停止执行,0为不限制时间 post_max_size = 150M #默认POST数据大小为8M,可以按实际情况修改 upload_max_filesize = 100M #默认上传文件最大为2M,可以按实际情况修改。 注:另外要说明的是,post_max_size 大于 upload_max_filesize 为佳 ``` **动态服务器编辑nginx连接php** ```bash 编辑nginx的配置文件: server { listen 80; server_name localhost; location ~ \.php$ { root /home/nginx/html; #指定网站目录 #fastcgi_pass 127.0.0.1:9000; #开启fastcgi连接php地址,在centos8中yum默认为unix方式,使用下面的配置 fastcgi_pass unix:/run/php-fpm/www.sock; fastcgi_index index.php; #指定默认文件 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; #站点根目录,取决于root配置项 include fastcgi_params; #包含fastcgi使用的常量 } } ``` **编辑php测试页面** ```php # cat /home/nginx/html/index.php ``` **本地访问测试** ![image-20220613224341842](assets/image-20220613224341842.png) ```ini 通过 expires 指令设置的缓存,主要是针对客户端浏览器的。如果我们能将静态资源的缓存设置在服务器端,当多个用户访问同一个资源时,缓存命中率及系统的性能将大大提升。 proxy_cache介绍:当nginx作为反向代理时,通常只有动态的请求,也就是不同的用户访问的同一个url看到的内容是不同的,这个时候才会交由上游服务器处理,但是有些内容可能是一段时间内是不会变化的,这个时候为了减轻上游服务器的压力,那么就让nginx把上游返回的内容缓存一段时间,比如缓存一天,在一天之内即是上游服务器内容发生了变化也不管,nginx只返回缓存到的内容给用户。 proxy_cache--实现服务器端缓存,主要设置在反向代理上面 ``` ```bash 3.配置nginx反向代理upstream,并实现服务器端缓存时间 upstream static { server 10.0.105.196:80 weight=1 max_fails=1 fail_timeout=60s; } upstream php { server 10.0.105.200:80 weight=1 max_fails=1 fail_timeout=60s; } proxy_cache_path /tmp/proxy_cache levels=1:2 keys_zone=proxy_cache:64m inactive=1d max_size=128m; server { listen 80; server_name localhost #动态资源加载 location ~ \.(php|jsp)$ { proxy_pass http://php; proxy_set_header Host $host:$server_port; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } #静态资源加载 location ~ .*\.(html|jpg|png|css|js)$ { proxy_pass http://static; proxy_set_header Host $host:$server_port; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_cache proxy_cache; #配置设置的缓存空间名称 proxy_cache_valid 200 302 304 30d ; #根据响应码设置缓存时间,超过这个时间即使缓存文件中有缓存数据,nginx也会回源请求新数据。 proxy_cache_key $host$uri$is_args$args; #对不同用户的请求展示不同的内容 } } 参数详解: proxy_cache_path 缓存文件路径 levels 设置缓存文件目录层次;levels=1:2 表示两级目录 keys_zone 设置缓存名字和共享内存大小.【在使用的地方要使用缓存名】 inactive 在指定缓存时间内没人访问则被删除 max_size 最大缓存空间,如果缓存空间满,默认覆盖掉缓存时间最长的资源。 ``` ```bash 当访问静态页面的时候location 匹配到 (html|jpg|png|js|css) 通过转发到静态服务器,静态服务通过location的正则匹配来处理请求。 当访问动态页面时location匹配到 .\php 结尾的文件转发到后端php服务处理请求。 ``` ### location指令 Nginx 的 HTTP 配置主要包括三个区块,结构如下: ```nginx http { # 协议块   include mime.types;   default_type application/octet-stream;   keepalive_timeout 65;   gzip on;   server { # 服务块       listen 80;       server_name localhost;       location / { # 请求块           root html;           index index.html index.htm;       }   } } 浏览器-->地址栏-->URI -->http:// --> 主机:80 -->http协议块的配置 --> server --> location -->页面内容-->返回客户端浏览器 ``` 1、location 区段 ```bash - location 是在 server 块中配置,根据不同的 URI 使用不同的配置,来处理不同的请求。 - location 是有顺序的,会根据不同请求配置的优先级来匹配的location 处理。 基本语法如下: location [=|~|~*|^~|@] pattern{……} ``` 2、location 前缀含义 ```shell = 表示精确匹配,优先级也是最高的 ^~ 表示uri以某个常规字符串开头,理解为匹配url路径即可 ~ 表示区分大小写的正则匹配 ~* 表示不区分大小写的正则匹配 !~ 表示区分大小写不匹配的正则 !~* 表示不区分大小写不匹配的正则 / 通用匹配,任何请求都会匹配到 @ 内部服务跳转 ``` **查找顺序和优先级** ```shell = 大于 ^~ 大于 ~|~* 大于 !~|!~* 大于 / 多个location配置的情况下匹配顺序为:首先匹配 =,其次匹配^~, 其次是按正则匹配,最后是交给 / 通用匹配。当有匹配成功时候,停止匹配,按当前匹配规则处理请求。 Named Location (location @): 使用@符号定义的命名位置块不匹配URI前缀,而是根据具体的用途或配置定义来执行内部重定向。它们通常不与请求URI的前缀直接匹配,因此不涉及前缀匹配的优先级。 ``` 3、location 配置示例 1、没有修饰符 表示:必须以指定模式开始 ```nginx server { listen 80; server_name localhost; location /abc { root /home/www/nginx; index 2.html; } 那么,如下是对的: http://192.168.1.9/abc ``` 2、=表示:必须与指定的模式精确匹配 ```nginx server { listen 80; server_name localhost; access_log /var/log/nginx/http_access.log main; location / { root /usr/share/nginx/html; index a.html index.htm; } location = / { root /usr/share/nginx/html; index b.html index.htm; } } 测试: http://192.168.1.9 =/ http://192.168.1.9/a.html / ``` 3、~ 表示:指定的正则表达式要区分大小写 ```nginx server { server_name localhost;   location ~ /ab* { root /home/www/nginx; index 2.html index.html; } } 测试访问: http://192.168.1.9/abc 不正确的 http://192.168.1.9/ABC ======================================== 如果将配置文件修改为 location ~ /ABC { root /home/www/nginx; index 2.html index.html; } 在创建目录和文件: [root@ansible-server html]# cd /home/www/nginx/ [root@ansible-server nginx]# mkdir ABC [root@ansible-server nginx]# vim ABC/2.html 访问: http://192.168.1.9/ABC/ 结论:~ 需要区分大小写。而且目录需要根据大小写定义。 ``` 4、^~和~*匹配案例 ```nginx location ^~ /static/ { root /usr/share/nginx/html; index f.html; } location ~* .jpg$ { root /usr/share/nginx/html; #上传图片到发布目录中 } 浏览器访问: http://192.168.198.144/static/ http://192.168.198.144/test.jpg ``` ```nginx location 区段匹配示例 location = / {   # 只匹配 / 的查询.   [ configuration A ] } location / {   # 匹配任何以 / 开始的查询,但是正则表达式与一些较长的字符串将被首先匹配。   [ configuration B ] } location ^~ /images/ {   # 匹配任何以 /images/ 开始的查询并且停止搜索,不检查正则表达式。   [ configuration C ] } location ~* \.(gif|jpg|jpeg)$ {   # 匹配任何以gif, jpg, or jpeg结尾的文件   [ configuration D ] } 各请求的处理如下例: / → configuration A /documents/document.html → configuration B /images/1.gif → configuration C /documents/1.jpg → configuration D ``` ### nginx 地址重写 rewrite **什么是Rewrite** ​ **Rewrite对称URL Rewrite,即URL重写,就是把传入Web的请求重定向到其他URL的过程** - URL Rewrite最常见的应用是URL伪静态化,是将动态页面显示为静态页面方式的一种技术。比如http://www.123.com/news/index.php?id=123 使用URLRewrite 转换后可以显示为 http://www.123.com/news/123.html - 从安全角度上讲,如果在URL中暴露太多的参数,无疑会造成一定量的信息泄漏,可能会被一些黑客利用,对你的系统造成一定的破坏,所以静态化的URL地址可以给我们带来更高的安全性。 - 实现网站地址跳转,例如用户访问360buy.com,将其跳转到jd.com。例如当用户访问tianyun.com的 80端口时,将其跳转到443端口。 **Rewrite 相关指令** 相关指令有 if、rewrite、set、return **if 语句** - 应用环境 ```shell server,location ``` 语法: ```shell if (condition) { … } if 可以支持如下条件判断匹配符号 ~ 正则匹配 (区分大小写) ~* 正则匹配 (不区分大小写) !~ 正则不匹配 (区分大小写) !~* 正则不匹配 (不区分大小写) -f 和!-f 用来判断是否存在文件 -d 和!-d 用来判断是否存在目录 -e 和!-e 用来判断是否存在文件或目录 -x 和!-x 用来判断文件是否可执行 在匹配过程中可以引用一些Nginx的全局变量 $args 请求中的参数; $document_root 针对当前请求的根路径设置值; $host 请求信息中的"Host",如果请求中没有Host行,则等于设置的服务器名; $limit_rate 对连接速率的限制; $request_method 请求的方法,比如"GET"、"POST"等; $remote_addr 客户端地址; $remote_port 客户端端口号; $remote_user 客户端用户名,认证用; $request_filename 当前请求的文件路径名(带网站的主目录/usr/local/nginx/html/images/a.jpg) $request_uri 当前请求的文件路径名(不带网站的主目录/images/a.jpg) $query_string 与$args相同; $scheme 用的协议,比如http或者是https $server_protocol 请求的协议版本,"HTTP/1.0"或"HTTP/1.1"; $server_addr 服务器地址,如果没有用listen指明服务器地址,使用这个变量将发起一次系统调用以取得地址(造成资源浪费); $server_name 请求到达的服务器名; $document_uri 与$uri一样,URI地址; $server_port 请求到达的服务器端口号; ``` **Rewrite flag** **rewrite** 指令根据表达式来重定向URI,或者修改字符串。可以应用于**server,location, if**环境下每行rewrite指令最后跟一个flag标记,支持的flag标记有: rewrite 正则 替换之后的内容 flag ```shell last 相当于Apache里的[L]标记,表示完成rewrite。默认为last。last 标记在本条 rewrite 规则执行完后,会对其所在的 server { … } 标签重新发起请求; break 本条规则匹配完成后,终止匹配,不再做后续的匹配,使用proxy_pass指令时,则必须使用break。 redirect 返回302临时重定向,浏览器地址会显示跳转后的URL地址 permanent 返回301永久重定向,浏览器地址会显示跳转后的URL地址 http://www.test.com/a.html http://www.test.com/a.htmlfdafkdjkajfkdjfk;ajd;kjf;dja;fjd;a ``` redirect 和 permanent区别则是返回的不同方式的重定向: ``` 对于客户端来说一般状态下是没有区别的。而对于搜索引擎,相对来说301的重定向更加友好,如果我们把一个地址采用301跳转方式跳转的话,搜索引擎会把老地址的相关信息带到新地址,同时在搜索引擎索引库中彻底废弃掉原先的老地址。 使用302重定向时,搜索引擎(特别是google)有时会查看跳转前后哪个网址更直观,然后决定显示哪个,如果它觉的跳转前的URL更好的话,也许地址栏不会更改。 www.baidu.com/bre ``` **last,break示例** ![1561898537620](assets/1561898537620.png) ```shell [root@localhost test]# cat /etc/nginx/conf.d/last_break.conf server { listen 80; server_name localhost; access_log /var/log/nginx/last.access.log main; location / { root /usr/share/nginx/html; index index.html index.htm; } location /break/ { root /usr/share/nginx/html; rewrite .* /test/break.html break; } location /last/ { root /usr/share/nginx/html; rewrite .* /test/last.html last; } location /test/ { root /usr/share/nginx/html; rewrite .* /test/test.html break; } } [root@localhost conf.d]# cd /usr/share/nginx/html/ [root@localhost html]# mkdir test [root@localhost html]# echo "last" > test/last.html [root@localhost html]# echo "break" > test/break.html [root@localhost html]# echo "test" > test/test.html http://10.0.105.196/break/break.html http://10.0.105.196/last/last.html ``` **Rewrite匹配参考示例** ```shell 本地解析host文件 # http://www.testpm.com/a/1.html ==> http://www.testpm.com/b/2.html location /a { root /html; index 1.html index.htm; rewrite .* /b/2.html permanent; } http://www.testpm.com/a/1 location /b { root /html; index 2.html index.htm; } 例2: # http://www.testpm.com/2019/a/1.html ==> http://www.testpm.com/2018/a/1.html location /2019/a { root /var/www/html; index 1.html index.hml; rewrite ^/2019/(.*)$ /2018/$1 permanent; } location /2018/a { root /var/www/html; index 1.html index.htl; } 例3: # http://www.qf.com/a/1.html ==> http://jd.com location /a { root /html; if ($host ~* www.qf.com ) { rewrite .* http://jd.com permanent; } } 例4: # http://www.qf.com/a/1.html ==> http://jd.com/a/1.html location /a { root /html; if ( $host ~* qf.com ){ rewrite .* http://jd.com$request_uri permanent; } } rewrite http://qf.com/test/a.html http://jd.com/test/a.html flag s / 正则表达式 / 替换后的内容 / g 例5: # http://www.tianyun.com/login/tianyun.html ==> http://www.tianyun.com/reg/login.html?user=tianyun location /login { root /usr/share/nginx/html; rewrite ^/login/(.*)\.html$ http://$host/reg/login.html?user=$1; } location /reg { root /usr/share/nginx/html; index login.html; } 例6: #http://www.tianyun.com/qf/11-22-33/1.html ==> http://www.tianyun.com/qf/11/22/33/1.html location /qf { rewrite ^/qf/([0-9]+)-([0-9]+)-([0-9]+)(.*)$ /qf/$1/$2/$3$4 permanent; } location /qf/11/22/33 { root /html; index 1.html; } ``` **set 指令** set 指令是用于定义一个变量,并且赋值 应用环境: ```shell server,location,if a=8 set a 8 ``` 应用示例 ```shell 例8: #http://alice.testpm.com ==> http://www.testpm.com/alice #http://jack.testpm.com ==> http://www.testpm.com/jack [root@nginx-server conf.d]# cd /usr/share/nginx/html/ [root@nginx-server html]# mkdir jack alice [root@nginx-server html]# echo "jack.." >> jack/index.html [root@nginx-server html]# echo "alice.." >> alice/index.html 本地解析域名host文件 10.0.105.202 www.testpm.com 10.0.105.202 alice.testpm.com 10.0.105.202 jack.testpm.com 编辑配置文件: server { listen 80; server_name www.testpm.com; location / { root /usr/share/nginx/html; index index.html index.htm; if ( $host ~* ^www.testpm.com$) { break; } if ( $host ~* "^(.*)\.testpm\.com$" ) { set $user $1; rewrite .* http://www.testpm.com/$user permanent; } } location /jack { root /usr/share/nginx/html; index index.html index.hml; } location /alice { root /usr/share/nginx/html; index index.html index.hml; } } ``` **return 指令** return 指令用于返回状态码给客户端 ```shell server,location,if ``` 应用示例: ```shell 例9:如果访问的.sh结尾的文件则返回403操作拒绝错误 server { listen 80; server_name www.testpm.cn; #access_log /var/log/nginx/http_access.log main; location / { root /usr/share/nginx/html; index index.html index.htm; } location ~* \.sh$ { return 403; } } 例10:80 ======> 443 :80转443端口 重点实验 server { listen 80; server_name www.testpm.cn; access_log /var/log/nginx/http_access.log main; return 301 https://www.testpm.cn$request_uri; } http://www.testpm.cn/abc/hello/index.html https://www.testpm.cn/abc/hello/index.html server { listen 443 ssl; server_name www.testpm.cn; access_log /var/log/nginx/https_access.log main; #ssl on; ssl_certificate /etc/nginx/cert/2447549_www.testpm.cn.pem; ssl_certificate_key /etc/nginx/cert/2447549_www.testpm.cn.key; ssl_session_timeout 5m; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP; ssl_prefer_server_ciphers on; location / { root /usr/share/nginx/html; index index.html index.htm; } } [root@nginx-server ~]# curl -I http://www.testpm.cn HTTP/1.1 301 Moved Permanently Server: nginx/1.16.0 Date: Wed, 03 Jul 2019 13:52:30 GMT Content-Type: text/html Content-Length: 169 Connection: keep-alive Location: https://www.testpm.cn/ ``` **Nginx 的 https ( rewrite )** ```shell server { listen 80; server_name *.vip9999.top vip9999.top; if ($host ~* "^www.vip9999.top$|^vip9999.top$" ) { return 301 https://www.vip9999.top$request_uri; } } # Settings for a TLS enabled server. server { listen 443 ssl; server_name www.vip9999.top; ssl_certificate cert/214025315060640.pem; ssl_certificate_key cert/214025315060640.key; ssl_session_cache shared:SSL:1m; ssl_session_timeout 10m; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; #pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 location ~ \.php$ { root /usr/share/nginx/html; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } ``` ### nginx 错误页面配置(扩展) nginx错误页面包括404 403 500 502 503 504等页面,只需要在server中增加以下配置即可: ```shell #error_page 404 403 500 502 503 504 /404.html; location = /404.html { root /usr/local/nginx/html; } ``` 注意: ```bash /usr/local/nginx/html/ 路径下必须有404.html这个文件!!! 404.html上如果引用其他文件的png或css就会有问题,显示不出来,因为其他文件的访问也要做配置; 为了简单,可以将css嵌入文件中,图片用base编码嵌入;如下: ``` base64 图片---转码 ```shell [root@localhost html]# vim 404.html 404

哎呀,找不到该页面啦!

请检查您的网络连接是否正常或者输入的网址是否正确

``` 展示效果; ![1561964133748](assets/1561964133748.png) 注意:测试时需要访问不存在页面才会报404,比如下路径需要把index.html页面删除并且测试时把index.html写入地址栏,不能空着。http://192.168.26.87/index.html ### Nginx 流量控制 **流量限制** (rate-limiting),我们可以用来限制用户在给定时间内HTTP请求的数量。流量限制可以用作安全目的,比如可以减慢暴力密码破解的速率,更常见的情况是该功能被用来保护上游应用服务器不被同时太多用户请求所压垮。 1、Nginx如何限流 Nginx的"流量限制"使用漏桶算法(leaky bucket algorithm),就好比,一个桶口在倒水,桶底在漏水的水桶。如果桶口倒水的速率大于桶底的漏水速率,桶里面的水将会溢出;同样,在请求处理方面,水代表来自客户端的请求,水桶代表根据”先进先出调度算法”(FIFO)等待被处理的请求队列,桶底漏出的水代表离开缓冲区被服务器处理的请求,桶口溢出的水代表被丢弃和不被处理的请求。 2、配置基本的限流--ngx_http_limit_req_module模块实现 “流量限制”配置两个主要的指令,`limit_req_zone`和`limit_req`,`limit_req_zone`指令设置流量限制和内存区域的参数,但实际上并不限制请求速率。所以需要通过添加`limit_req`指令启用流量限制,应用在特定的`location`或者`server`块。(示例中,对于”/login/”的所有请求)。 `limit_req_zone`指令通常在HTTP块中定义,它需要以下三个参数: ```ini -Key - 定义应用限制的请求特性。示例中的 Nginx 变量$binary_remote_addr,保存客户端IP地址的二进制形式。 -Zone - 定义用于存储每个IP地址状态以及被限制请求URL访问频率的内存区域。通过zone=keyword标识区域的名字(自定义),以及冒号后面跟区域大小。16000个IP地址的状态信息,大约需要1MB。 -Rate - 连接请求。在示例中,速率不能超过每秒1个请求。 ``` 实战 ```shell limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s; upstream myweb { server 10.0.105.196:80 weight=1 max_fails=1 fail_timeout=1; } server { listen 80; server_name localhost; location /login { limit_req zone=mylimit; proxy_pass http://myweb; proxy_set_header Host $host:$server_port; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } ``` ```shell 10.0.105.196配置: server { listen 80; server_name localhost; location /login { root /usr/share/nginx/html; index index.html index.html; } } ``` **测试** ```ini 客户端安装压力测试工具 [root@nginx-yum ~]# yum install httpd-tools [root@nginx-yum ~]# ab -n1000 -c2 http://10.0.105.196/ -n 请求数 -c 并发数 代理机器看错误日志: [root@nginx-server ~]# tail -f /var/log/nginx/error.log 2019/09/10 07:32:09 [error] 1371#0: *1095 limiting requests, excess: 0.390 by zone "mylimit", client: 10.0.105.196, server: localhost, request: "GET / HTTP/1.0", host: "10.0.105.196" ``` 日志字段 ```bash - limiting requests - 表明日志条目记录的是被“流量限制”请求 - excess - 每毫秒超过对应“流量限制”配置的请求数量 - zone - 定义实施“流量限制”的区域 - client - 发起请求的客户端IP地址 - server - 服务器IP地址或主机名 - request - 客户端发起的实际HTTP请求 - host - HTTP报头中host的值 ``` ```ini 查看访问日志出现503 [root@nginx-server nginx]# tail -f /var/log/nginx/access.log 10.0.105.196 - - [10/Sep/2019:07:32:09 +0800] "GET / HTTP/1.0" 503 197 "-" "ApacheBench/2.3" "-" ``` 实战二 ```ini limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s; upstream myweb { server 10.0.105.196:80 weight=1 max_fails=1 fail_timeout=1; } server { listen 80; server_name localhost; location /login { #limit_req zone=mylimit; limit_req zone=mylimit burst=5; #limit_req zone=mylimit burst=5 nodelay; proxy_pass http://myweb; proxy_set_header Host $host:$server_port; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } burst=5 表示最大延迟请求数量不大于5。超出的请求返回503状态码。 客户端测试--burst [root@nginx-yum ~]# ab -n1000 -c50 http://10.0.105.195/ 代理机器上面看日志 [root@nginx-server ~]# tail -f /var/log/nginx/access.log 10.0.105.196 - - [10/Sep/2019:08:05:10 +0800] "GET / HTTP/1.0" 503 197 "-" "ApacheBench/2.3" "-" 10.0.105.196 - - [10/Sep/2019:08:05:11 +0800] "GET / HTTP/1.0" 200 2 "-" "ApacheBench/2.3" "-" nodelay:不延迟转发请求。速度变快 客户端测试--burst [root@nginx-yum ~]# ab -n1000 -c50 http://10.0.105.195/ 总结: 如果不加nodelay只有burst的时候只会延迟转发请求超过限制的请求出现503错误 如果nodelay和burst参数都有不会延迟转发请求并且超出规定的请求次数会返回503 ``` 4、发送到客户端的错误代码 一般情况下,客户端超过配置的流量限制时,Nginx响应状态码为**503(Service Temporarily Unavailable)**。可以使用`limit_req_status`指令来设置为其它状态码(例如下面的**404**状态码): ```shell limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s; upstream myweb { server 10.0.105.196:80 weight=1 max_fails=1 fail_timeout=1; } server { listen 80; server_name localhost; location /login { limit_req zone=mylimit; limit_req_status 404; proxy_pass http://myweb; proxy_set_header Host $host:$server_port; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } ``` ### nginx 访问控制 1、nginx 访问控制模块 ```bash (1)基于IP的访问控制:http_access_module (2)基于用户的信任登录:http_auth_basic_module ``` 2、基于IP的访问控制 **配置语法** ```shell Syntax:allow address | all; default:默认无 Context:http,server,location Syntax:deny address | all; default:默认无 Context:http,server,location =================================================== allow 允许 //ip或者网段 deny 拒绝 //ip或者网段 ``` **配置测试** 编辑`/etc/nginx/conf.d/access_mod.conf`内容如下: ```shell [root@192 ~]# vim /etc/nginx/conf.d/access_mod.conf server { listen 80; server_name localhost; location / { root /usr/share/nginx/html; index index.html index.hml; deny 192.168.1.8; allow all; } } [root@192 ~]# nginx -t [root@192 ~]# nginx -s reload #需要注意: 1.按顺序匹配,已经被匹配的ip或者网段,后面不再被匹配。 2.如果先允许所有ip访问,再定义拒绝访问。那么拒绝访问不生效。 3.默认为allow all ``` 宿主机IP为`192.168.1.8`,虚拟机IP为`192.168.1.11`,故这里禁止宿主机访问,允许其他所有IP访问。 宿主机访问`http://192.168.1.11`,显示`403 Forbidden`。 当然也可以反向配置,同时也可以使用IP网段的配置方式,如`allow 192.168.1.0/24;`,表示满足此网段的IP都可以访问。 **指定`location`拒绝所有请求** 如果你想拒绝某个指定URL地址的所有请求,只需要在`location`块中配置`deny` **all**指令: ```shell [root@192 ~]# vim /etc/nginx/conf.d/access_mod.conf server { listen 80; server_name localhost; location / { root /usr/share/nginx/html; index index.html index.hml; deny all; #拒绝所有 } } [root@192 ~]# nginx -t [root@192 ~]# nginx -s reload ``` 3、基于用户的信任登录 (2)基于用户的信任登录模块:http_auth_basic_module 有时我们会有这么一种需求,就是你的网站的某些页面不希望公开,我们希望的是某些特定的客户端可以访问。那么我们可以在访问时要求进行身份认证,就如给你自己的家门加一把锁,以拒绝那些不速之客。 **配置语法** ```shell Syntax:auth_basic string | off; default:auth_basic off; Context:http,server,location Syntax:auth_basic_user_file file; default:默认无 Context:http,server,location file:存储用户名密码信息的文件。 ``` **配置示例** ```shell [root@192 ~]# vim /etc/nginx/conf.d/auth_mod.conf server { listen 80; server_name localhost; location ~ /admin { root /var/www/html; index index.html index.hml; auth_basic "Auth access test!"; auth_basic_user_file /etc/nginx/auth_conf; } } [root@192 ~]# nginx -t [root@192 ~]# nginx -s reload [root@192 ~]# mkdir /var/www/html #创建目录 [root@192 ~]# vim /var/www/html/index.html #创建文件 ``` `auth_basic`不为`off`,开启登录验证功能,`auth_basic_user_file`加载账号密码文件。 **建立口令文件** ```shell [root@192 ~]# yum install -y httpd-tools #htpasswd 是开源 http 服务器 apache httpd 的一个命令工具,用于生成 http 基本认证的密码文件 [root@192 ~]# htpasswd -cm /etc/nginx/auth_conf user10 # -c 创建解密文件,-m MD5加密(新版本的apache不用-m可默认加密) [root@192 ~]# htpasswd -m /etc/nginx/auth_conf user20 [root@192 ~]# cat /etc/nginx/auth_conf user10:$apr1$MOa9UVqF$RlYRMk7eprViEpNtDV0n40 user20:$apr1$biHJhW03$xboNUJgHME6yDd17gkQNb0 ``` **访问测试** ![1561996355328](assets/1561996355328.png) 使用 limit_rate 限制客户端传输数据的速度 编辑/etc/nginx/nginx.conf ```bash location / { root /var/www/nginx/; index index.html index.htm; limit_rate 2k; #对每个连接的限速为2k/s } 重启服务 ``` ### nginx 变量 Nginx的配置文件使用语法的就是一门微型的编程语言。既然是编程语言,一般也就少不了“变量”这种东西。 ##### 1、nginx变量简介 ```ini - 所有的 Nginx变量在 Nginx 配置文件中引用时都须带上 $ 前缀 - 在 Nginx 配置中,变量只能存放一种类型的值,而且也只存在一种类型,那就是字符串类型 ``` 所有的变量值都可以通过这种方式引用: ```ini $变量名 ``` ##### 2、nginx 变量的定义和使用 nginx中的变量分为两种,自定义变量与内置预定义变量 ###### 1、自定义变量 **1、声明变量** 可以在sever,http,location等标签中使用set命令声明变量,语法如下 ```shell set $变量名 变量值 set $A 8 $A ``` **注意:** ```ini - nginx 中的变量必须都以$开头 - nginx 的配置文件中所有使用的变量都必须是声明过的,否则 nginx 会无法启动并打印相关异常日志 ``` ###### nginx安装echo模块 ```shell 查看已经安装的nginx的版本 [root@192 ~]# nginx -V 上传或者下载一个相同版本的nginx包 [root@192 ~]# ls anaconda-ks.cfg nginx-1.16.0.tar.gz 下载echo模块的安装包 [root@192 ~]# wget https://github.com/openresty/echo-nginx-module/archive/v0.61.tar.gz [root@192 ~]# ls anaconda-ks.cfg nginx-1.16.0.tar.gz v0.61.tar.gz 解压到相同路径下: [root@192 ~]# tar xzf nginx-1.16.0.tar.gz -C /usr/local/ [root@192 ~]# tar xzf v0.61.tar.gz -C /usr/local/ 安装编译工具 [root@192 ~]# cd /usr/local/ [root@192 local]# yum -y install pcre pcre-devel openssl openssl-devel gcc gcc-c++ zlib zlib-devel gd-devel 添加模块: [root@192 local]# cd nginx-1.16.0/ 添加上原来已经有的参数和新添加的模块: [root@192 nginx-1.16.0]# ./configure --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie' --add-module=/usr/local/echo-nginx-module-0.61 [root@192 nginx-1.16.0]# make #编译,不要make install 否则会覆盖原来的文件 [root@192 nginx-1.16.0]# mv /usr/sbin/nginx /usr/sbin/nginx_bak #将原来的nignx备份 [root@192 nginx-1.16.0]# cp objs/nginx /usr/sbin/ 拷贝nignx [root@192 nginx-1.16.0]# systemctl restart nginx #启动 [root@192 nginx-1.16.0]# nginx -V 查看模块是否添加成功 nginx version: nginx/1.16.0 built by gcc 4.8.5 20150623 (Red Hat 4.8.5-36) (GCC) built with OpenSSL 1.0.2k-fips 26 Jan 2017 TLS SNI support enabled configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie' --add-module=/usr/local/echo-nginx-module-0.61 ``` **2、配置 $foo=hello** ```shell [root@192 ~]# cd /etc/nginx/conf.d/ [root@192 conf.d]# vim echo.conf server { listen 80; server_name localhost; location /test { set $foo hello; echo "foo: $foo"; } } ``` 输出 ```shell [root@192 conf.d]# nginx -s reload [root@192 conf.d]# curl localhost/test foo: hello ``` Nginx 变量的创建只能发生在 Nginx 配置加载的时候,或者说 Nginx 启动的时候。而赋值操作则只会发生在请求实际处理的时候。这意味着不创建而直接使用变量会导致启动失败。 ###### 2、内置预定义变量 内置预定义变量即无需声明就可以使用的变量,通常包括一个http请求或响应中一部分内容的值,以下为一些常用的内置预定义变量 | **变量名** | **定义** | | ------------------- | ------------------------------------------------------------ | | $arg_PARAMETER | GET请求中变量名PARAMETER参数的值。 | | $args | 这个变量等于GET请求中的参数。例如,foo=123&bar=blahblah;这个变量只可以被修改 | | $binary_remote_addr | 二进制码形式的客户端地址。 | | $body_bytes_sent | 传送页面的字节数 | | $content_length | 请求头中的Content-length字段。 | | $content_type | 请求头中的Content-Type字段。 | | $cookie_COOKIE | cookie COOKIE的值。 | | $document_root | 当前请求在root指令中指定的值。 | | $document_uri | 与$uri相同。 | | $host | 请求中的主机头(Host)字段,如果请求中的主机头不可用或者空,则为处理请求的server名称(处理请求的server的server_name指令的值)。值为小写,不包含端口。 | | $hostname | 机器名使用 gethostname系统调用的值 | | $http_HEADER | HTTP请求头中的内容,HEADER为HTTP请求中的内容转为小写,-变为_(破折号变为下划线),例如:$http_user_agent(Uaer-Agent的值); | | $sent_http_HEADER | HTTP响应头中的内容,HEADER为HTTP响应中的内容转为小写,-变为_(破折号变为下划线),例如: $sent_http_cache_control, $sent_http_content_type…; | | $is_args | 如果$args设置,值为"?",否则为""。 | | $limit_rate | 这个变量可以限制连接速率。 | | $nginx_version | 当前运行的nginx版本号。 | | $query_string | 与$args相同。 | | $remote_addr | 客户端的IP地址。 | | $remote_port | 客户端的端口。 | | $remote_user | 已经经过Auth Basic Module验证的用户名。 | | $request_filename | 当前连接请求的文件路径,由root或alias指令与URI请求生成。 | | $request_body | 这个变量(0.7.58+)包含请求的主要信息。在使用proxy_pass或fastcgi_pass指令的location中比较有意义。 | | $request_body_file | 客户端请求主体信息的临时文件名。 | | $request_completion | 如果请求成功,设为"OK";如果请求未完成或者不是一系列请求中最后一部分则设为空。 | | $request_method | 这个变量是客户端请求的动作,通常为GET或POST。包括0.8.20及之前的版本中,这个变量总为main request中的动作,如果当前请求是一个子请求,并不使用这个当前请求的动作。 | | $request_uri | 这个变量等于包含一些客户端请求参数的原始URI,它无法修改,请查看$uri更改或重写URI。 | | $scheme | 所用的协议,比如http或者是https,比如rewrite ^(.+)$ $scheme://example.com$1 redirect; | | $server_addr | 服务器地址,在完成一次系统调用后可以确定这个值,如果要绕开系统调用,则必须在listen中指定地址并且使用bind参数。 | | $server_name | 服务器名称。 | | $server_port | 请求到达服务器的端口号。 | | $server_protocol | 请求使用的协议,通常是HTTP/1.0或HTTP/1.1。 | | $uri | 请求中的当前URI(不带请求参数,参数位于args),不同于浏览器传递的args),不同于浏览器传递的args),不同于浏览器传递的request_uri的值,它可以通过内部重定向,或者使用index指令进行修改。不包括协议和主机名,例如/foo/bar.html | ### nginx 监控 **1、nginx的基础监控** ```ini - 进程监控 - 端口监控 ``` 注意: 这两个是必须要加在zabbix监控,加触发器有问题及时告警。 nginx 提供了 ngx_http_stub_status_module.这个 模块提供了基本的监控功能 **2、监控的指标** 1、基本活跃指标 Accepts(接受)、Handled(已处理)、Requests(请求数)是一直在增加的计数器。Active(活跃)、Waiting(等待)、Reading(读)、Writing(写)随着请求量而增减。 2、服务器错误率 通过监控固定时间间隔内的错误代码(4XX代码表示客户端错误,5XX代码表示服务器端错误)。 3、请求处理时间 请求处理时间也可以被记录在 access log 中,通过分析 access log,统计请求的平均响应时间。 ----$request_time 变量 1、nginx Stub Status 监控模块安装  先使用命令查看是否已经安装这个模块: ```shell # -V大写会显示版本号和模块等信息、v小写仅显示版本信息 [root@localhost ~]# nginx -V ``` 注意:是如果没有此模块,需要重新安装,编译命令如下: ```shell ./configure --with-http_stub_status_module ``` 具体的使用方法是在执行 ./configure 时,指定 --with-http_stub_status_module,然后通过配置: ```shell [root@localhost ~]# vim /etc/nginx/conf.d/status.conf server { listen 80; server_name localhost; location /nginx-status { stub_status on; access_log on; } } ``` 2、nginx 状态查看 配置完成后在浏览器中输入http://10.0.105.207/nginx-status 查看显示信息如下: ```shell Active connections: 2 server accepts handled requests 26 26 48 Reading: 0 Writing: 1 Waiting: 1 ``` 3、Stub Status 参数说明 ![1562035977477](assets/1562035977477.png) ```shell connection #连接数,tcp连接 request #http请求,GET/POST/DELETE/UPLOAD ``` ![1567697012994](assets/1567697012994.png) ```ini nginx总共处理了26个连接,成功创建26次握手,也就是成功的连接数connection. 总共处理了48个请求 失败连接=(总连接数(accepts)-成功连接数(handled))(相等表示中间没有失败的), Reading : nginx读取到客户端的Header信息数。请求头 -----速度快。 Writing :nginx返回给客户端的Header信息数。响应头 Waiting :开启keep-alive的情况下,意思就是Nginx说已经处理完正在等候下一次请求指令的驻留连接。 ``` 基于脚本监控nginx的端口 ```ini [root@nginx-server ~]# vim check_port.sh #!/usr/bin/bash curl -I http://127.0.0.1 &> /dev/null if [ $? -ne 0 ];then echo "nginx 未运行,正在启动中..." sleep 1 systemctl start nginx echo "正在检查nginx是否启动..." port=`netstat -lntp | grep nginx |awk '{print $4}' | awk -F':' '{print $NF}'` echo "nginx已经启动,端口为: $port" fi ``` ```bash 访问状态脚本 # vim nginx.sh curl 192.168.26.87 > cache.txt 2>/dev/null case $1 in connections) cat cache.txt | awk 'NR==1{print $3}' ;; accepts) cat cache.txt | awk 'NR==3{print $1}' ;; handled) cat cache.txt | awk 'NR==3{print $2}' ;; requests) cat cache.txt | awk 'NR==3{print $3}' ;; Reading) cat cache.txt | awk 'NR==4{print $2}' ;; Writing) cat cache.txt | awk 'NR==4{print $4}' ;; Waiting) cat cache.txt | awk 'NR==4{print $6}' ;; *) echo 参数错误 ;; esac ``` Alias 虚拟目录 ```nginx server { listen 80; server_name localhost; location /test { root /var/www/html; index index.html; } www.baidu.com/test url/var/www/html/test/index.html location /qfedu { alias /var/www/nginx; #访问http://x.x.x.x/qfedu时实际上访问是/var/www/nginx/index.html index index.html; } } ``` `root`和`alias`的主要区别是: ```bash #使用root,实际的路径就是:root值 + location值。root会将完整的url映射进文件路径。 #使用alias,实际的路径就是:alias值。alias只会将localhost后的url映射到文件路径。 #alias只能位于location块中,root可以放在http,server,location块中 ``` ### HTTPS 原理(扩展) HTTPS(全称:HyperText Transfer Protocol over Secure Socket Layer),其实 HTTPS 并不是一个新鲜协议,Google 很早就开始启用了,初衷是为了保证数据安全。 国内外的大型互联网公司很多也都已经启用了HTTPS,这也是未来互联网发展的趋势。 1、加密算法 **对称加密** ```ini A要给B发送数据 1,A做一个对称密钥 2,使用密钥给文件加密 3,发送加密以后的文件和钥匙 4,B拿钥匙解密 ``` 加密和解密都是使用的同一个密钥。 **非对称加密** ---- 公钥加密,私钥解密 A要给B发送数据 ```ini 1.B做一对非对称的密钥 2.发送公钥给A 3.A拿公钥对数据进行加密 4.发送加密后的数据给B 5.B拿私钥解密 ``` 1. 哈希算法 将任意长度的信息转换为较短的固定长度的值,通常其长度要比信息小得多。 例如:MD5、SHA-1、SHA-2、SHA-256 等 2. 数字签名 ```ini 签名就是在信息的后面再加上一段内容(信息经过hash后的值),可以证明信息没有被修改过。hash值一般都会加密后(也就是签名)再和信息一起发送,以保证这个hash值不被修改。 ``` 2、HTTPS 协议介绍 - HTTP 协议(HyperText Transfer Protocol,超文本传输协议):是客户端浏览器与Web服务器之间的应用层通信协议 。 - HTTPS 协议(HyperText Transfer Protocol over Secure Socket Layer):可以理解为HTTP+SSL/TLS, 即 HTTP 下加入 SSL 层,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL,用于安全的 HTTP 数据传输. ![1562050089966](assets/1562050089966.png) - 如上图所示 HTTPS 相比 HTTP 多了一层 SSL/TLS **SSL/TLS :SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS与SSL在传输层为数据通讯进行加密提供安全支持。** ```ini SSL协议可分为两层:SSL握手协议(SSL Handshake Protocol):它建立在SSL记录协议之上,用于在实际的数据传输开始前,通讯双方进行身份认证、协商加密算法、交换加密密钥等。---相当于连接 SSL记录协议(SSL Record Protocol):它建立在可靠的传输协议(如TCP)之上,为高层协议提供数据封装、压缩、加密等基本功能的支持。---相当于通信 ``` **SSL协议提供的服务主要有:** ```ini ssl:身份认证和数据加密。保证数据完整性 1)认证用户和服务器,确保数据发送到正确的客户机和服务器; 2)加密数据以防止数据中途被窃取; 3)维护数据的完整性,确保数据在传输过程中不被改变。 ``` 3、HTTPS 原理 1、HTTP 访问过程 ![1562050123147](assets/1562050123147.png) 如上图所示,HTTP请求过程中,客户端与服务器之间没有任何身份确认的过程,数据全部明文传输,“裸奔”在互联网上,所以很容易遭到黑客的攻击,如下: ![1562050246969](assets/1562050246969.png) 可以看到,客户端发出的请求很容易被黑客截获,如果此时黑客冒充服务器,则其可返回任意信息给客户端,而不被客户端察觉。 **所以 HTTP 传输面临的风险有:** ```ini - 窃听风险:黑客可以获知通信内容。 - 篡改风险:黑客可以修改通信内容。 - 冒充风险:黑客可以冒充他人身份参与通信。 ``` 那有没有一种方式既可以安全的获取公钥,又能防止黑客冒充呢? 那就需要用到终极武器了:SSL 证书(申购) - 证书:.crt, .pem - 私钥:.key - 证书请求文件:.csr ![1562050492512](assets/1562050492512.png) 如上图所示,在第 ② 步时服务器发送了一个SSL证书给客户端,SSL 证书中包含的具体内容有: (1)证书的发布机构CA (2)证书的有效期 (3)公钥 (4)证书所有者 (5)签名 ----- 签名就可以理解为是钞票里面的一个防伪标签。 **客户端在接受到服务端发来的SSL证书时,会对证书的真伪进行校验,以浏览器为例说明如下:** ```ini (1)首先浏览器读取证书中的证书所有者、有效期等信息进行一一校验 (2)浏览器开始查找操作系统中已内置的受信任的证书发布机构CA,与服务器发来的证书中的颁发者CA比对,用于校验证书是否为合法机构颁发 (3)如果找不到,浏览器就会报错,说明服务器发来的证书是不可信任的。 (4)如果找到,那么浏览器就会从操作系统中取出 颁发者CA 的公钥,然后对服务器发来的证书里面的签名进行解密 (5)浏览器使用相同的hash算法计算出服务器发来的证书的hash值,将这个计算的hash值与证书中签名做对比 (6)对比结果一致,则证明服务器发来的证书合法,没有被冒充 (7)此时浏览器就可以读取证书中的公钥,用于后续加密了 (8)client与web协商对称加密算法,client生成对称加密密钥并使用web公钥加密,发送给web服务器,web服务器使用web私钥解密 (9)使用对称加密密钥传输数据,并校验数据的完整性 ``` 4、所以通过发送SSL证书的形式,既解决了公钥获取问题,又解决了黑客冒充问题,一箭双雕,HTTPS加密过程也就此形成 **所以相比HTTP,HTTPS 传输更加安全** (1) 所有信息都是加密传播,黑客无法窃听。 (2) 具有校验机制,一旦被篡改,通信双方会立刻发现。 (3) 配备身份证书,防止身份被冒充。 3、HTTPS 总结 **综上所述,相比 HTTP 协议,HTTPS 协议增加了很多握手、加密解密等流程,虽然过程很复杂,但其可以保证数据传输的安全。** HTTPS 缺点: 1. SSL 证书费用很高,以及其在服务器上的部署、更新维护非常繁琐 2. HTTPS 降低用户访问速度(多次握手) 3. 网站改用HTTPS 以后,由HTTP 跳转到 HTTPS 的方式增加了用户访问耗时(多数网站采用302跳转) 4. HTTPS 涉及到的安全算法会消耗 CPU 资源,需要增加大量机器(https访问过程需要加解密) 4、CA 机构 CA(Certificate Authority)证书颁发机构主要负责证书的颁发、管理以及归档和吊销。证书内包含了拥有证书者的姓名、地址、电子邮件帐号、公钥、证书有效期、发放证书的CA、CA的数字签名等信息。**证书主要有三大功能:加密、签名、身份验证。** 阿里云申请配置ssl证书---实战 1.准备一台阿里云服务器,我的机器在香港 ![image-20200213200532113](assets/image-20200213200532113.png) 2.准备一个域名 ![image-20200213200455861](assets/image-20200213200455861.png) 3.申请ssl证书 ![image-20200213200630056](assets/image-20200213200630056.png) ![image-20200213200649217](assets/image-20200213200649217.png) ![image-20200213200720968](assets/image-20200213200720968.png) ![image-20200213200802120](assets/image-20200213200802120.png) ![image-20200213200818583](assets/image-20200213200818583.png) ![image-20200213200845265](assets/image-20200213200845265.png) ![image-20200213200859612](assets/image-20200213200859612.png) ![image-20200213201008494](assets/image-20200213201008494.png) **开始配置信息** ![image-20200213201131777](assets/image-20200213201131777.png) ![image-20200213201151813](assets/image-20200213201151813.png) ![image-20200213201339745](assets/image-20200213201339745.png) ![image-20200213201357363](assets/image-20200213201357363.png) 到这需要等待大约10几分钟!然后刷新 ![image-20200213202534828](assets/image-20200213202534828.png) 先查看帮助文档 ![image-20200213202726173](assets/image-20200213202726173.png) ![image-20200213202749549](assets/image-20200213202749549.png) 然后在下载 ![image-20200213202618176](assets/image-20200213202618176.png) 阿里云配置证书案例: ```shell yum安装nginx ----略 将证书上传到服务器中 1.首先需要在服务器创建对应的文件夹,参考命令如下 [root@nginx ~]# cd /etc/nginx/ && mkdir cert 2.在服务器创建完成对应文件夹之后,将证书文件复制到服务器中 [root@nginx nginx]# cd [root@nginx ~]# ls 2447549_www.testpm.cn_nginx.zip [root@nginx ~]# yum install -y unzip [root@nginx ~]# unzip 2447549_www.testpm.cn_nginx.zip Archive: 2447549_www.testpm.cn_nginx.zip Aliyun Certificate Download inflating: 2447549_www.testpm.cn.pem inflating: 2447549_www.testpm.cn.key [root@nginx ~]# ls 2447549_www.testpm.cn.key 2447549_www.testpm.cn_nginx.zip 2447549_www.testpm.cn.pem [root@nginx ~]# cp 2447549_www.testpm.cn* /etc/nginx/cert/ [root@nginx ~]# cd /etc/nginx/cert/ 改名: [root@nginx cert]# mv 2447549_www.testpm.cn.key www.testpm.cn.key [root@nginx cert]# mv 2447549_www.testpm.cn.pem www.testpm.cn.pem 证书配置 证书复制完成之后,可以对nginx配置文件进行更改,使用vim命令 [root@nginx ~]# cd /etc/nginx/conf.d/ [root@nginx conf.d]# vim nginx_ssl.conf [root@nginx conf.d]# cat /etc/nginx/conf.d/nginx_ssl.conf server { listen 443 ssl; #https端口 server_name www.testpm.cn; access_log /var/log/nginx/https_access.log main; ssl_certificate /etc/nginx/cert/www.testpm.cn.pem; #指定证书路径 ssl_certificate_key /etc/nginx/cert/www.testpm.cn.key; #指定私钥路径 ssl_session_timeout 5m; #配置用于SSL会话的缓存 ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #指定使用的协议 ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP; #密码指定为OpenSSL支持的格式 ssl_prefer_server_ciphers on; #设置协商加密算法。 location / { root /usr/share/nginx/html; index index.html index.htm; } } ``` 需要给域名做一个解析,香港的服务器添加一个A记录即可 ![image-20200213210056748](assets/image-20200213210056748.png) ![image-20200213210116172](assets/image-20200213210116172.png) ![image-20200213210202138](assets/image-20200213210202138.png) ![image-20200213210312751](assets/image-20200213210312751.png) ![image-20200213210344925](assets/image-20200213210344925.png) 解析完成之后大约需要等待3-5分钟 **测试访问** ![image-20200213205917877](assets/image-20200213205917877.png) ![image-20200213205951802](assets/image-20200213205951802.png) 访问成功! ### Nginx 性能优化 当我需要进行性能优化时,说明我们服务器无法满足日益增长的业务,需要从以下几个方面进行探讨 1、当前系统结构瓶颈 首先需要了解的是当前系统瓶颈,用的是什么,跑的是什么业务。里面的服务是什么样子,每个服务最大支持多少并发。 可以通过查看当前cpu负荷,内存使用率,来做简单判断。还可以通过操作系统的一些工具来判断当前系统性能瓶颈,如分析对应的日志,查看请求数量。也可以通过nginx http_stub_status_module模块来查看对应的连接数,总握手次数,总请求数。 2、了解业务模式 虽然我们是在做性能优化,但还是要熟悉业务,最终目的都是为业务服务的。我们要了解每一个接口业务类型是什么样的业务,比如电子商务抢购模式,这种情况平时流量会很小,但是到了抢购时间,流量一下子就会猛涨。也要了解系统层级结构,每一层在中间层做的是代理还是动静分离,还是后台进行直接服务。 3、系统与nginx性能优化 对相关的系统瓶颈及现状有了一定的了解之后,就可以根据影响性能方面做一个全体的评估和优化。 - 网络(网络流量、是否有丢包,网络的稳定性都会影响用户请求) - 系统(系统负载、内存使用率、系统的稳定性、硬件磁盘是否有损坏) - 服务(连接优化、内核性能优化、http服务请求优化都可以在nginx中根据业务来进行设置) - 程序(接口性能、处理请求速度、每个程序的执行效率) - 数据库、底层服务 上面列举出来每一级都会有关联,也会影响整体性能,这里主要关注的是nginx服务这一层。 #### 文件句柄 在linux/unix操作系统中一切皆文件,我们的设备是文件,文件是文件,文件夹也是文件。当我们用户每发起一次请求,就会产生一个文件句柄。文件句柄可以简单的理解为`文件句柄就是一个索引`。文件句柄就会随着请求量的增多,进程调用频繁增加,那么产生的文件句柄也就会越多。 fd file descriptor 文件描述符 文件句柄 a.txt b.txt 1000 1000 limit -n 系统默认对文件句柄是有限制的,不可能会让一个进程无限制的调用句柄。因为系统资源是有限的,操作系统默认使用的文件句柄是1024个句柄。 **设置方式** - 系统全局性修改 - 用户局部性修改 - 进程局部性修改 **系统全局性修该和用户局部性修改** ```shell [root@nginx-server ~]# vim /etc/security/limits.conf ``` ```shell #* soft core 0 #* hard rss 10000 #@student hard nproc 20 #@faculty soft nproc 20 #@faculty hard nproc 50 #ftp hard nproc 0 #@student - maxlogins 4 #root只是针对root这个用户来限制,soft只是发提醒,操作系统不会强制限制,一般的站点设置为一万左右就ok了 root soft nofile 65535 root hard nofile 65535 # *代表通配符 所有的用户 * soft nofile 25535 * hard nofile 25535 #hard硬控制,到达设定值后,操作系统会采取机制对当前进程进行限制,这个时候请求就会受到影响 ``` root代表是root用户,*代表的是所有用户,后面的数字就是文件句柄大小。大家可以根据个人业务来进行设置。 **进程局部性修改** ```shell [root@nginx-server ~]# vim /etc/nginx/nginx.conf user nginx; #运行nginx的用户。可以修改 worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; worker_rlimit_nofile 65535; #进程限制,配置Nginx worker进程最大打开文件数 events { worker_connections 1024; #一个worker进程的并发 } ... ``` `worker_rlimit_nofile` 是在进程上面进行限制。 ```ini ulimit 命令---用于查看系统限制的值 # -a  显示目前资源限制的设定。 # -n <文件数目>  指定同一时间最多可开启的文件数。 2、ulimit -n 65535 #修改打开句柄数 ---临时 ``` #### nginx通用配置优化 ```nginx #将nginx进程设置为普通用户,为了安全考虑 user nginx; #当前启动的worker进程,官方建议是与系统核心数一致 worker_processes auto; #将work进程绑定到每个cpu的核数上 worker_cpu_affinity auto; #日志配置成warn error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; #针对 nginx 句柄的文件限制,配置Nginx worker进程最大打开文件数>worker_connections值 worker_rlimit_nofile 35535; #事件模型 events { #使用epoll内核模型 use epoll; #每一个进程可以处理多少个连接,如果是多核可以将连接数调高 worker_processes * 1024 worker_connections 2048; } http { server_tokens off; #隐藏nginx的版本号 include /etc/nginx/mime.types; default_type application/octet-stream; charset utf-8; #设置字符集,服务端返回给客户端报文的时候,Nginx强行将报文转码为utf-8 #设置日志输出格式,根据自己的情况设置 log_format main '$http_user_agent' '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for" ' '"$args" "$request_uri"'; access_log /var/log/nginx/access.log main; sendfile on; # 用于开启文件高效传输模式,一般设置为on,若nginx是用来进行磁盘IO负载应用时,可以设置为off,降低系统负载 tcp_nopush on; # 减少网络报文段数量,当有数据时,先别着急发送, 确保数据包已经装满数据, 避免了网络拥塞 tcp_nodelay on; # 提高I/O性能,确保数据尽快发送, 提高数据传输效率 keepalive_timeout 65; #设置长连接的超时时间,请求完成之后还要保持连接多久. open_file_cache max=35535 inactive=20s #这个将为打开文件指定缓存,默认是没有启用的,max指定缓存数量,建议和打开文件数一致,inactive 是指经过多长时间文件没被请求后删除缓存。 ######## #Gzip module gzip on; #文件压缩默认可以打开.告诉nginx采用gzip压缩的形式发送数据。这将会减少发送的数据量。 gzip_disable "MSIE [1-6]\."; #对于有些浏览器不能识别压缩,需要过滤如ie6 gzip_min_length 1k; #允许压缩的最小字节数 gzip_http_version 1.1; #设置识别 http 协议版本,默认是 1.1 gzip_types text/css text/xml application/javascript #用来指定压缩的类型,‘text/html’类型总是会被压缩。 autoindex on; //用于http或者location模块 开启目录列表访问,合适下载服务器,默认关闭。 Nginx默认是不允许列出整个目录的。如需此功能,打开nginx.conf文件,在location server 或 http段中加入autoindex on; 另外两个参数最好也加上去: autoindex_exact_size off; 默认为on,显示出文件的确切大小,单位是bytes。 改为off后,显示出文件的大概大小,单位是kB或者MB或者GB autoindex_localtime on; 默认为off,显示的文件时间为GMT时间。 改为on后,显示的文件时间为文件的服务器时间 include /etc/nginx/conf.d/*.conf; } ``` ### Nginx 平滑升级(扩展) 1、Nginx 平滑升级原理 ```ini (1)在不停掉老进程的情况下,启动新进程。 (2)老进程负责处理仍然没有处理完的请求,但不再接受处理请求。 (3)新进程接受新请求。 (4)老进程处理完所有请求,关闭所有连接后,停止。 这样就很方便地实现了平滑升级。一般有两种情况下需要升级 nginx,一种是确实要升级 nginx 的版本,另一种是要为 nginx 添加新的模块 ``` 2、Nginx信号简介 主进程支持的信号 ```ini - TERM, INT: 立刻退出 - QUIT: 等待工作进程结束后再退出 - KILL: 强制终止进程 - HUP: 重新加载配置文件,使用新的配置启动工作进程,并逐步关闭旧进程。 - USR1: 重新打开日志文件 - USR2: 启动新的主进程,实现热升级 - WINCH: 逐步关闭工作进程 ``` 工作进程支持的信号 ```ini - TERM, INT: 立刻退出 - QUIT: 等待请求处理结束后再退出 - USR1: 重新打开日志文件 ``` 3、nginx 平滑升级实战 查看现有的 nginx 编译参数 ```shell [root@nginx-server ~]# /usr/local/nginx/sbin/nginx -V ``` 按照原来的编译参数安装 nginx 的方法进行安装,**只需要到 make,千万不要 make install** 。如果make install 会将原来的配置文件覆盖(还有另外的方法,直接把新版安装到另一个目录,然后拷贝新版启动文件到旧版目录) ```shell [root@nginx-server ~]# cd /usr/local/nginx-1.16.0/ [root@nginx-server nginx-1.16.0]# ./configure --prefix=/usr/local/nginx --group=nginx --user=nginx --sbin-path=/usr/local/nginx/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/tmp/nginx/client_body --http-proxy-temp-path=/tmp/nginx/proxy --http-fastcgi-temp-path=/tmp/nginx/fastcgi --pid-path=/var/run/nginx.pid --lock-path=/var/lock/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_gzip_static_module --with-pcre --with-http_realip_module --with-stream --with-http_image_filter_module [root@nginx-server nginx-1.16.0]# make make完之后会在解压目录下产生一个objs目录,里面就是新版的nginx二进制启动文件 ``` 备份原 nginx 二进制文件 备份二进制文件和 nginx 的配置文件(期间nginx不会停止服务) ```shell [root@nginx-server nginx-1.16.0]# mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx_$(date +%F) ``` 复制新版nginx二进制文件进入旧版nginx安装目录 ```shell [root@nginx-server nginx-1.16.0]# cp /usr/local/nginx-1.16.0/objs/nginx /usr/local/nginx/sbin/ ``` 测试新版本的nginx是否正常 ```shell [root@nginx-server nginx-1.16.0]# /usr/local/nginx/sbin/nginx -t ``` 给nginx发送平滑迁移信号(若不清楚pid路径,请查看nginx配置文件) ```shell [root@nginx-server ~]# kill -USR2 `cat /var/run/nginx.pid` ``` 查看nginx pid,会出现一个nginx.pid.oldbin ```shell [root@nginx-server ~]# ll /var/run/nginx.pid* -rw-r--r-- 1 root root 5 Jul 1 11:29 /var/run/nginx.pid -rw-r--r-- 1 root root 5 Jul 1 09:54 /var/run/nginx.pid.oldbin ``` 从容关闭旧的Nginx进程 ```shell [root@nginx-server ~]# kill -WINCH `cat /var/run/nginx.pid.oldbin` ``` 结束工作进程,完成此次升级 ```shell [root@nginx-server ~]# kill -QUIT `cat /var/run/nginx.pid.oldbin` ``` 验证Nginx是否升级成功 ```shell [root@nginx-server ~]# /usr/local/nginx/sbin/nginx -V ``` # Last和break 在NGINX中,`rewrite`是用于重写URL的指令,可以在服务器块或 location 块中使用。`rewrite` 指令通常有两个重要选项:`break` 和 `last`。这两个选项用于控制重写操作的行为。以下是对它们的详细解释: 1. `break` 选项: - 当使用 `rewrite ... break;` 时,它会立即停止当前 location 块内的 rewrite 过程。 - 如果有其他 rewrite 规则定义在同一个 location 块内,这些规则将不会再被执行。 - 这个选项通常用于阻止后续的 rewrite 规则在当前 location 块中执行。它可以用于执行某种条件检查后立即中断处理。 示例: ```nginx location /example/ { rewrite ^/example/old(/.*)$ /example/new$1 break; rewrite ^/example/other(/.*)$ /example/something$1; # 这个不会被执行 } ``` 在上面的示例中,如果请求匹配 `/example/old/...`,第一条 rewrite 规则将被执行,并使用 `break` 选项终止当前 location 块中的 rewrite 处理,不会继续执行第二条 rewrite 规则。 2. `last` 选项: - 当使用 `rewrite ... last;` 时,它会终止当前 rewrite 指令的处理,但会重新启动请求的处理,同时将请求的URI与新的URI传递给新的 location。 - 这可以用于执行重定向操作,将请求传递到新的 location 块,而不终止整个请求处理。 - 如果有其他 rewrite 规则定义在同一个 location 块内,它们也将会被重新执行。 示例: ```nginx location /example/ { rewrite ^/example/old(/.*)$ /example/new$1 last; rewrite ^/example/other(/.*)$ /example/something$1; # 这个也会被执行 } ``` 在上面的示例中,如果请求匹配 `/example/old/...`,第一条 rewrite 规则将被执行,但使用 `last` 选项,它会重新启动请求处理,并传递给新的 location 或匹配的 location 块。然后,第二条 rewrite 规则也会被执行。 综上所述,`break` 用于终止当前 location 块内的 rewrite 处理,而 `last` 用于重新启动请求的处理并将请求传递给新的 location。这两个选项在不同情况下非常有用,可以根据需要选择使用哪个。 **Last和Break练习示例** 示例1-无break和last 请求:访问/1.html 结果:最终会匹配到b.html 执行顺序:连续执行两次rewrite后,匹配到location /3.html,最终匹配到b.html server{ listen 80; server_name test.com; root /tmp; location / { rewrite /1.html /2.html; rewrite /2.html /3.html; } location /2.html { rewrite /2.html /a.html; } location /3.html { rewrite /3.html /b.html; } } 示例2-break在location外 请求:访问/1.html 结果:最终返回403 执行顺序:因为rewrite后有break,所以不再匹配后面的rewrite了,但会继续匹配后面的location。 server{ listen 80; server_name test.com; root /tmp; rewrite /1.html /2.html break; rewrite /2.html /3.html; location /2.html { return 403; } } 示例3-break在location中 请求:访问/1.html 结果:最终得到2.html 执行顺序:在location块中匹配到rewrite /1.html /2.html break;后不再执行任何语句,包括当前location块中的语句。 server{ listen 80; server_name test.com; root /tmp/123.com; location / { rewrite /1.html /2.html break; rewrite /2.html /3.html; } location /2.html { rewrite /2.html /a.html; } location /3.html { rewrite /3.html /b.html; } } 示例4-last 请求:访问/1.html 结果:最终得到a.html 执行顺序:遇到了last的后,会再次进行匹配,最终得到a.html。 server{ listen 80; server_name test.com; root /tmp/123.com; location / { rewrite /1.html /2.html last; rewrite /2.html /3.html; } location /2.html { rewrite /2.html /a.html; } location /3.html { rewrite /3.html /b.html; } } # 制作CA证书(扩展) ## 证书制作 RHEL5、RHEL6 、RHEL7中在/etc/pki/tls/certs 目录有个脚本可以帮助我们简化证书生成的过程 \#cd /etc/pki/tls/certs \#make server.key //生成私钥 \#openssl rsa -in server.key -out server.key //去除密码以便使用时不询问密码 注:rsa是一种采用非对称密钥的加密算法 ​ \#make server.csr //生成证书颁发机构,用于颂发公钥 ​ \#openssl x509 -in server.csr -req -signkey server.key -days 365 -out server.crt //颁发公钥 ​ 注:x509是一种非常通用的证书格式 ## Nginx配置证书使用 由于我们并不是去 CA 证书中心申请的公钥,所以在使用的时候,客户端浏览器会跳出未受信任的警告。如果你 money 够多,请去 CA 申请。 server { listen 443; ​ #listen 443 ssl; 1.26版本以上使用此配置 并且取消下面ssl的开关行配置 ​ server_name web.wing.com; ​ ssl on; # 1.26 版本需要删除本行配置 ​ **ssl_certificate /etc/pki/tls/certs/server.crt;** **​ ssl_certificate_key /etc/pki/tls/certs/server.key;** #指定证书所存放的路径 ​ ssl_session_timeout 5m; ​ ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ​ **ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;** # 密码指定为OpenSSL支持的格式,Nginx模板配置不可用,注意修改此行 ​ ssl_prefer_server_ciphers on; ​ location / { ​ root /wing/html; ​ index index.html index.htm; ​ } ​ } 1.生成一个CA中心 2.有自己的网站(web服务器) 3.生成证书请求 4.把证书请求发送给CA中心 5.CA中心给证书请求签名 6.把签名成功证书下发给WEB服务器 7.在web上配置证书生效(创建一个https的虚拟主机,指定指定私钥和证书的位置) 8.浏览器访问web服务器443端口,下载证书到客户端浏览器** 9.浏览器去CA中心验证证书真假 10.客户端生成自己的对称加密密钥,连同网页内容的请求一起发给服务器 11.客户端会使用WEB服务器的公钥对对称加密密钥进程加密 12.服务器对客户端发来的加密对称密钥解密并使用解密出来的对称密钥对将要传输的数据加密,然后传给客户端