Nginx学习笔记

web服务基础介绍

正常情况下的单次web服务访问流程
nginx访问

用户访问体验统计

互联网存在用户速度体验的1-3-10原则,即01秒最优,13秒较优,3~10秒比较慢,10秒以上用户无法接受。用户放弃一个产品的代价很低,只是换一个URL而已。
全球最大搜索引擎 Google:慢500ms = 20% 将放弃访问。 全球最大的电商零售网站 亚马逊:慢100ms = 1% 将放弃交易

应用程序工作模式:

httpd MPM(Multi-Processing Module,多进程处理模块)模式:
prefork:进程模型,两级结构,主进程master负责生成子进程,每个子进程负责响应一个请求
worker:线程模型,三级结构,主进程master负责生成子进程,每个子进程负责生成多个线程,每个线程响应一个请求
event:线程模型,三级结构,主进程master负责生成子进程,每个子进程生成多个线程,每个线程响应一个请求,但是增加了一个监听线程,用于解决在设置了keep-alived场景下线程的空等待问题。

Nginx(Master+Worker)模式:
主进程
工作进程

服务端I/O

nginx访问

I/O: Input/Output, IOPS (Input/Output Per Second)即每秒的输入输出量(或读写次数),是衡量磁盘性能的主要指标之一。
IOPS: 单位时间内系统能处理的I/O请求数量,一般以每秒处理的I/O请求数量为单位,I/O请求通常为读或写数据操作请求。

一次完整的I/O是用户空间的进程数据与内核空间的内核数据的报文的完整交换,但是由于内核空间与用户空间是严格隔离的,所以其数据交换过程中不能由用户空间的进程直接调用内核空间的内存数据,而是需要经历一次从内核空间中的内存数据copy到用户空间的进程内存当中,所以简单说I/O就是把数据从内核空间中的内存数据复制到用户空间中进程的内存当中; 而网络通信就是网络协议栈到用户空间进程的IO就是网络IO

磁盘I/O是进程向内核发起系统调用,请求磁盘上的某个资源比如是文件或者是图片,然后内核通过相应的驱动程序将目标图片加载到内核的内存空间,加载完成之后把数据从内核内存再复制给进程内存,如果是比较大的数据也需要等待时间。
每次IO,都要经由两个阶段:
第一步:将数据从文件先加载至内核内存空间(缓冲区),等待数据准备完成,时间较长
第二步:将数据从内核缓冲区复制到用户空间的进程的内存中,时间较短

系统I/O模型:

同步/异步:关注的是消息通信机制,即在等待一件事情的处理结果时,被调用者是否提供完成通知。
同步:synchronous,调用者等待被调用者返回消息后才能继续执行,如果被调用者不提供消息返回则为同步,同步需要调用者主动询问事情是否处理完成。
异步:asynchronous,被调用者通过状态、通知或回调机制主动通知调用者被调用者的运行状态

同步:进程发出请求调用后,等内核返回响应以后才继续下一个请求,即如果内核一直不返回数据,那么进程就一直等。
异步:进程发出请求调用后,不等内核返回响应,接着处理下一个请求,Nginx是异步的。

阻塞/非阻塞:关注调用者在等待结果返回之前所处的状态
阻塞:blocking,指IO操作需要彻底完成后才返回到用户空间,调用结果返回之前,调用者被挂起,干不了别的事情。
非阻塞:nonblocking,指IO操作被调用后立即返回给用户一个状态值,无需等到IO操作彻底完成,最终的调用结果返回之前,调用者不会被挂起,可以去做别的事情。

异步非阻塞:程序进程向内核发送IO调用后,不用等待内核响应,可以继续接受其他请求,内核调用的IO如果不能立即返回,内核会继续处理其他事物,直到IO完成后将结果通知给内核,内核在将IO完成的结果返回给进程,期间进程可以接受新的请求,内核也可以处理新的事物,因此相互不影响,可以实现较大的同时并实现较高的IO复用,因此异步非阻塞使用最多的一种通信方式

网络I/O模型

阻塞型、非阻塞型、复用型、信号驱动型、异步

实现方式

Nginx支持在多种不同的操作系统实现不同的事件驱动模型,但是其在不同的操作系统甚至是不同的系统版本上面的实现方式不尽相同,主要有以下实现方式:

1、select:
select库是在linux和windows平台都基本支持的 事件驱动模型库,并且在接口的定义也基本相同,只是部分参数的含义略有差异,最大并发限制1024,是最早期的事件驱动模型。
2、poll:
在Linux 的基本驱动模型,windows不支持此驱动模型,是select的升级版,取消了最大的并发限制,在编译nginx的时候可以使用–with-poll_module和–without-poll_module这两个指定是否编译select库。
3、epoll:默认
epoll是库是Nginx服务器支持的最高性能的事件驱动库之一,是公认的非常优秀的事件驱动模型,它和select和poll有很大的区别,epoll是poll的升级版,但是与poll的效率有很大的区别.
epoll的处理方式是创建一个待处理的事件列表,然后把这个列表发给内核,返回的时候在去轮训检查这个表,以判断事件是否发生,epoll支持一个进程打开的最大事件描述符的上限是系统可以打开的文件的最大数,同时epoll库的IO效率不随描述符数目增加而线性下降,因为它只会对内核上报的“活跃”的描述符进行操作。

epoll是在Linux 2.6内核中提出的select和poll的增强版本
支持水平触发LT和边缘触发ET,最大的特点在于边缘触发,它只告诉进程哪些fd刚刚变为就需态,并且只会通知一次
使用“事件”的就绪通知方式,通过epoll_ctl注册fd,一旦该fd就绪,内核就会采用类似callback的回调机制来激活该fd,epoll_wait便可以收到通知。优点:
1 没有最大并发连接的限制:能打开的FD的上限远大于1024(1G的内存能监听约10万个端口),具体查看/proc/sys/fs/file-max,此值和系统内存大小相关
2 效率提升:非轮询的方式,不会随着FD数目的增加而效率下降;只有活跃可用的FD才会调用callback函数,即epoll最大的优点就在于它只管理“活跃”的连接,而跟连接总数无关内存拷贝,利用mmap(Memory Mapping)加速与内核空间的消息传递;即epoll使用mmap减少复制开销

epoll:Linux 2.6内核中提出的select和poll的增强版本
支持水平触发LT和边缘触发ET,最大的特点在于边缘触发,它只告诉进程哪些fd刚刚变为就需态,并且只会通知一次
使用“事件”的就绪通知方式,通过epoll_ctl注册fd,一旦该fd就绪,内核就会采用类似callback的回调机制来激活该fd,epoll_wait便可以收到通知,优点:
1 没有最大并发连接的限制:能打开的FD的上限远大于1024(1G的内存能监听约10万个端口),具体查看/proc/sys/fs/file-max,此值和系统内存大小相关
2 效率提升:非轮询的方式,不会随着FD数目的增加而效率下降;只有活跃可用的FD才会调用callback函数,即epoll最大的优点就在于它只管理“活跃”的连接,而跟连接总数无关内存拷贝,利用mmap(Memory Mapping)加速与内核空间的消息传递;即epoll使用mmap减少复制开销

Nginx基础

Nginx:engine X ,2002年,开源,商业版 Nginx是免费的、开源的、高性能的HTTP和反向代理服务器、邮件代理服务器、以及TCP/UDP代理服务器 解决C10K问题(10K Connections),http://www.ideawu.net/blog/archives/740.html
官网:http://nginx.org
nginx的其它的二次发行版:
Tengine:由淘宝网发起的Web服务器项目。它在Nginx的基础上,针对大访问量网站的需求,添加了很多高级功能和特性。Tengine的性能和稳定性已经在大型的网站如淘宝网,天猫商城等得到了很好的检验。它的最终目标是打造一个高效、稳定、安全、易用的Web平台。从2011年12月开始,Tengine成为一个开源项目
官网 http://tengine.taobao.org/
OpenResty:基于Nginx 与 Lua 语言的高性能 Web 平台, 章亦春开发,官网:http://openresty.org/cn/

Nginx功能介绍:

静态的web资源服务器html,图片,js,css,txt等静态资源 结合FastCGI/uWSGI/SCGI等协议反向代理动态资源请求 http/https协议的反向代理 imap4/pop3协议的反向代理 tcp/udp协议的请求转发(反向代理)

基础特性:

模块化设计,较好的扩展性
高性能
支持热部署:不停机更新配置文件,升级版本,更换日志文件
低内存消耗:10000个keep-alive连接模式下的非活动连接,仅需2.5M内存
event-driven, aio, mmap, sendfile

基本功能:(面试:Nginx的版本1.8.1 用什么代理?要清楚了解)

静态资源的web服务器
http协议反向代理服务器  (tcp支持是在1.9.0后)
pop3/imap4协议反向代理服务器
FastCGI(LNMP),uWSGI(python)等协议
模块化(非DSO),如zip,SSL模块

和web服务相关的功能:

虚拟主机(server):可以基于域名,ip,端口实现
支持 keep-alive 和管道连接(利用一个连接做多次请求)
访问日志(支持基于日志缓冲提高其性能)
url rewirte
路径别名:访问别名时跳转到指定位置
基于IP及用户的访问控制
支持速率限制及并发数限制
重新配置和在线升级而无须中断客户的工作进程
Memcached 的 GET 接口

Nginx组织结构:

web请求处理机制:
1、多进程方式:服务器每接收到一个客户端请求就有服务器的主进程生成一个子进程响应客户端,直到用户关闭连接,这样的优势是处理速度快,子进程之间相互独立,但是如果访问过大会导致服务器资源耗尽而无法提供请求。
2、多线程方式:与多进程方式类似,但是每收到一个客户端请求会有服务进程派生出一个线程来个客户方进行交互,一个线程的开销远远小于一个进程,因此多线程方式在很大程度减轻了web服务器对系统资源的要求,但是多线程也有自己的缺点,即当多个线程位于同一个进程内工作的时候,可以相互访问同样的内存地址空间,所以他们相互影响,一旦主进程挂掉则所有子线程都不能工作了,IIS服务器使用了多线程的方式,需要间隔一段时间就重启一次才能稳定。

Nginx是多进程组织模型,而且是一个由Master主进程和Worker工作进程组成。

主进程(master process)的功能:
读取Nginx 配置文件并验证其有效性和正确性
建立、绑定和关闭socket连接
按照配置生成、管理和结束工作进程
接受外界指令,比如重启、升级及退出服务器等指令
不中断服务,实现平滑升级,重启服务并应用新的配置
开启日志文件,获取文件描述符
不中断服务,实现平滑升级,升级失败进行回滚处理
编译和处理perl脚本

工作进程(woker process)的功能:
接受处理客户的请求
将请求以此送入各个功能模块进行处理
IO调用,获取响应数据
与后端服务器通信,接收后端服务器的处理结果
缓存数据,访问缓存索引,查询和调用缓存数据
发送请求结果,响应客户的请求
接收主程序指令,比如重启、升级和退出等

进程间通信:

工作进程是由主进程生成的,主进程使用fork()函数,在Nginx服务器启动过程中主进程根据配置文件决定启动工作进程的数量,然后建立一张全局的工作表用于存放当前未退出的所有的工作进程,主进程生成工作进程后会将新生成的工作进程加入到工作进程表中,并建立一个单向的管道并将其传递给工作进程,该管道与普通的管道不同,它是由主进程指向工作进程的单项通道,包含了主进程向工作进程发出的指令、工作进程ID、工作进程在工作进程表中的索引和必要的文件描述符等信息。
主进程与外界通过信号机制进行通信,当接收到需要处理的信号时,它通过管道向相关的工作进程发送正确的指令,每个工作进程都有能力捕获管道中的可读事件,当管道中有可读事件的时候,工作进程就会从管道中读取并解析指令,然后采取相应的执行动作,这样就完成了主进程与工作进程的交互。

工作进程之间的通信原理基本上和主进程与工作进程之间的通信是一样的,只要工作进程之间能够取得彼此的信息,建立管道即可通信,但是由于工作进程之间是完全隔离的,因此一个进程想要直到另外一个进程的状态信息就只能通过主进程来设置了。

为了实现工作进程之间的交互,主进程在生成工作进程只之后,在工作进程表中进行遍历,将该新进程的ID以及针对该进程建立的管道句柄传递给工作进程中的其他进程,为工作进程之间的通信做准备,当工作进程1向工作进程2发送指令的时候,首先在主进程给它的其他工作进程工作信息中找到2的进程ID,然后将正确的指令写入指向进程2的管道,工作进程2捕获到管道中的事件后,解析指令并进行相关操作,这样就完成了工作进程之间的通信。

Nginx模块介绍:

核心模块:是 Nginx服务器正常运行 必不可少的模块,提供错误日志记录、配置文件解析、事件驱动机制、进程管理 等核心功能
标准HTTP模块:提供 HTTP 协议解析相关的功能,比如: 端口配置、网页编码设置、HTTP响应头设置等等
可选HTTP模块:主要用于扩展标准的 HTTP 功能,让 Nginx 能处理一些特殊的服务,比如: Flash 多媒体传输 、解析 GeoIP 请求、 网络传输压缩 、 安全协议 SSL 支持等
邮件服务模块:主要用于支持Nginx 的 邮件服务 ,包括对 POP3 协议、 IMAP 协议和 SMTP协议的支持
第三方模块:是为了扩展 Nginx 服务器应用,完成开发者自定义功能,比如: Json 支持、 Lua 支持等

nginx高度模块化,但其模块早期不支持DSO机制;1.9.11版本支持动态装载和卸载

Nginx安装:

Nginx的安装版本分为开发版(mainline version)、稳定版(stable version)和过期版(legacy version)
Nginx安装可以使用yum(epel)或源码安装,但是推荐使用源码,一是yum的版本比较旧,二是编译安装可以更方便自定义相关路径,三是使用源码编译可以自定义相关功能,更方便业务的上的使用

&& 源码安装需要提前准备标准的编译器,GCC的全称是(GNU Compiler collection),由GNU开发,并以GPL即LGPL许可,是自由的类UNIX即苹果电脑Mac OS X操作系统的标准编译器,因为GCC原本只能处理C语言,所以原名为GNU C语言编译器,后来得到快速发展,可以处理C++,Fortran,pascal,objective-C,java以及Ada等其他语言,此外还需要Automake工具,以完成自动创建Makefile的工作,Nginx的一些模块需要依赖第三方库,比如pcre(支持rewrite),zlib(支持gzip模块)和openssl(支持ssl模块)等。

Nginx 编译安装:

&& 所有配置文件都在一个目录方便备份: tar zcvf nginx.tar.gz ./nginx
&& 编译安装的软件 二进制文件+配置文件+静态资源 就能启动

准备编译安装的基础环境:

1
[root@s2 ~]# yum install -y vim lrzsz tree screen psmisc lsof tcpdump wget ntpdate gcc gcc-c++ glibc glibc-devel pcre pcre-devel openssl  openssl-devel systemd-devel net-tools iotop bc zip unzip zlib-devel bash-completion nfs-utils automake libxml2 libxml2-devel libxslt libxslt-devel perl perl-ExtUtils-Embed

gcc:GNU Compiler Collection,可以编译C和C++源代码等,它是GNU开发的C和C++以及其他很多种语言的编译器(最早的时候只能编译C,后来很快进化成一个编译多种语言的集合,如Fortran、Pascal、Objective-C、Java、Ada、 Go等。)
gcc 在编译C++源代码的阶段,只能编译 C++ 源文件,而不能自动和 C++ 程序使用的库链接(编译过程分为编译、链接两个阶段,注意不要和可执行文件这个概念搞混,相对可执行文件来说有三个重要的概念:编译(compile)、链接(link)、加载(load)。源程序文件被编译成目标文件,多个目标文件连同库被链接成一个最终的可执行文件,可执行文件被加载到内存中运行)。因此,通常使用 g++ 命令来完成 C++ 程序的编译和连接,该程序会自动调用 gcc 实现编译。
gcc-c++也能编译C源代码,只不过把会把它当成C++源代码,后缀为.c的,gcc把它当作是C程序,而g++当作是c++程序;后缀为.cpp的,两者都会认为是c++程序,注意,虽然c++是c的超集,但是两者对语法的要求是有区别的。
automake:一个从Makefile.am文件自动生成Makefile.in的工具。为了生成Makefile.in,automake还需用到perl,由于automake创建的发布完全遵循GNU标准,所以在创建中不需要perl。
libtool是一款方便生成各种程序库的工具。
pcre pcre-devel:在Nginx编译需要 PCRE(Perl Compatible Regular Expression),因为Nginx的Rewrite模块和HTTP 核心模块会使用到PCRE正则表达式语法。
zlip zlib-devel:nginx启用压缩功能的时候,需要此模块的支持。
openssl openssl-devel:开启SSL的时候需要此模块的支持。

安装Nginx:

官方源码包下载地址:https://nginx.org/en/download.html

1
2
3
4
[root@s2 ~]# cd /usr/local/src/
[root@s2 src]# wget https://nginx.org/download/nginx-1.12.2.tar.gz
[root@s2 src]# tar xf nginx-1.12.2.tar.gz
[root@s2 src]# cd nginx-1.12.2/

编译是为了检查系统环境是否符合编译安装的要求,比如是否有gcc编译工具,是否支持编译参数当中的模块,并根据开启的参数等生成Makefile文件为下一步做准备:生产中编译参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@s2 nginx-1.12.2]#./configure --prefix=/apps/nginx \
--user=nginx \
--group=nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \ # 传递用户真实ip
--with-http_stub_status_module \ # 状态页,不开启当利用状态页配合zebix做监控就不支持
--with-http_gzip_static_module \ # 静态页面会压缩传递给用户
--with-pcre \
--with-stream \ | #\
--with-stream_ssl_module \ # |--> 开启tcp负载功能 1.9.1以上版本支持
--with-stream_realip_module | #/
[root@s2 nginx-1.12.2]# make #编译步骤,根据Makefile文件生成相应的模块
[root@s2 nginx-1.12.2]# make install #创建目录,并将生成的模块和文件复制到相应的目录:
[root@s2 nginx-1.12.2]# useradd nginx -s /sbin/nologin -u 2000
[root@s2 nginx-1.12.2]# chown nginx.nginx -R /apps/nginx/

nginx完成安装以后,有四个主要的目录:
conf:保存nginx所有的配置文件,其中nginx.conf是nginx服务器的最核心最主要的配置文件,其他的.conf则是用来配置nginx相关的功能的,例如fastcgi功能使用的是fastcgi.conf和fastcgi_params两个文件,配置文件一般都有个样板配置文件,是文件名.default结尾,使用的使用将其复制为并将default去掉即可。
html:目录中保存了nginx服务器的web文件,但是可以更改为其他目录保存web文件,另外还有一个50x的web文件是默认的错误页面提示页面。
logs:用来保存nginx服务器的访问日志错误日志等日志,logs目录可以放在其他路径,比如/var/logs/nginx里面。
sbin:保存nginx二进制启动脚本,可以接受不同的参数以实现不同的功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@s1 ~]# nginx -h
nginx version: nginx/1.12.2
Usage: nginx [-?hvVtTq] [-s signal] [-c filename] [-p prefix] [-g directives]
Options:
-?,-h : this help
-v : show version and exit
-V : show version and configure options then exit #显示版本和编译参数,yum安装查看官方编译参数
-t : test configuration and exit #测试配置文件是否异常
-T : test configuration, dump it and exit #测试并打印生效配置文件
-q : suppress non-error messages during configuration testing #静默模式
-s signal : send signal to a master process: stop, quit, reopen, reload #发送信号 -
p prefix : set prefix path (default: /usr/share/nginx/) #指定Nginx 目录
-c filename : set configuration file (default: /etc/nginx/nginx.conf) #配置文件路径
-g directives : set global directives out of configuration file #设置全局指令

验证版本及编译参数:

1
2
3
4
5
6
[root@s2 nginx-1.12.2]# /apps/nginx/sbin/nginx -V
nginx version: nginx/1.12.2
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=/apps/nginx --user=nginx --group=nginx --withhttp_ssl_module --with-http_v2_module --with-http_realip_module --withhttp_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module

验证Nginx:

1
[root@s1 ~]# nginx -t 		#更改完配置文件必进行此操作,防止配置错误down

配置Nginx:

默认配置文件:/etc/nginx/nginx.conf

1
2
3
4
5
[root@s1 ~]# ps -ef | grep nginx
root 8650 1 0 17:43 ? 00:00:00 nginx: master process /usr/sbin/nginx
nginx 8651 8650 0 17:43 ? 00:00:00 nginx: worker process
nginx 8652 8650 0 17:43 ? 00:00:00 nginx: worker process
root 8858 2785 0 17:47 pts/0 00:00:00 grep --color=auto nginx

服务启动方面

停止,重载 服务:
/app/nginx/sbin/nginx -s stop | reload

&& java.php等动态资源 需停止服务,清除缓存,启动服务
systemd启动:
scp /usr/lib/systemd/system/nginx.service 192.18.35.72:/usr/lib/systemd/system/nginx.service
变更配置文件,注释掉PID,编译路径•••
systemctl daemon-reload

Nginx启动脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@s1 ~]# cat /usr/lib/systemd/system/nginx.service
[Unit]
Description=The nginx HTTP and reverse proxy server
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
PIDFile=/apps/nginx/logs/nginx.pid
# Nginx will fail to start if /run/nginx.pid already exists but has the wrong
# SELinux context. This might happen when running `nginx -t` from the cmdline.
# https://bugzilla.redhat.com/show_bug.cgi?id=1268621
ExecStartPre=/usr/bin/rm -f /apps/nginx/logs/nginx.pid
ExecStartPre=/apps/nginx/sbin/nginx -t
ExecStart=/apps/nginx/sbin/nginx -c /apps/nginx/conf/nginx.conf
ExecReload=/bin/kill -s HUP $MAINPID
#KillSignal=SIGQUIT
#TimeoutStopSec=5
KillMode=process
PrivateTmp=true
[Install]
WantedBy=multi-user.target

配置Nginx

主配置文件:nginx.conf,子配置文件: include conf.d/*.conf
fastcgi, uwsgi,scgi等协议相关的配置文件
mime.types:支持的mime类型,MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型,MIME消息能包含文本、图像、音频、视频以及其他应用程序专用的数据,是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。

主配置文件的配置指令:directive value [value2 …];
(1) 指令必须以分号结尾
(2) 支持使用配置变量
内建变量:由Nginx模块引入,可直接引用
自定义变量:由用户使用set命令定义
set variable_name value;
引用变量:$variable_name

全局配置端:
对全局生效,主要设置nginx的启动用户/组,启动的工作进程数量,工作模式,Nginx的PID路径,日志路径等
events:
主要影响nginx服务器与用户的网络连接,比如是否允许同时接受多个网络连接,使用哪种事件驱动模型处理请求,每个工作进程可以同时支持的最大连接数,是否开启对多工作进程下的网络连接进行序列化等
http:
缓存、代理和日志格式定义等绝大多数功能和第三方模块都可以在这设置,http块可以包含多个server块,而一个server块中又可以包含多个location块
server: 设置一个虚拟机主机,可以包含自己的全局快,同时也可以包含多个locating模块。比如本虚拟机监听的端口、本虚拟机的名称和IP配置,多个server 可以使用一个端口,比如都使用80端口提供web服务。可以配置文件引入、MIME-Type定义、日志自定义、是否启用sendfile、连接超时时间和单个链接的请求上限等
location: 其实是server的一个指令,为nginx服务器提供比较多而且灵活的指令都是在location中提现的,主要是基于nginx接收到的请求字符串,对用户请求的UIL进行匹配,并对特定的指令进行处理,包括地址重定向、数据缓存和应答控制等功能都是在这部分实现,另外很多第三方模块的配置也是在location模块中配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
[root@s2 ~]# grep -v "#" /apps/nginx/conf/nginx.conf | grep -v "^$"
user nginx nginx; # 集群架构中确保使用用户同步,否则经常出现403 permission deny
worker_processes [number|auto]; #启动Nginx work进程的数量,生产不用auto,cpu几核就启动几个,不要大于cpu内核
worker_cpu_affinity 0001 0010 0100 1000; # 将Nginx工作进程绑定到指定的CPU核心,默认不进行进程绑定
可以保证此进程不会运行在其他核心上,极大减少了nginx的工作进程在不同的cpu
核心上的来回跳转,减少了CPU对进程的资源分配与回收以及内存管理等
有效的提升nginx服务器的性能。验证见下面示例
pid /apps/nginx/logs/nginx.pid; 文件记录nginx主进程pid
error_log /apps/nginx/logs/error.log error; # 语法:error_log file [debug | info | notice | warn | error | crit |alert | emerg]
worker_priority 0; # 工作进程优先级,-20~19
worker_rlimit_nofile 65536; # 这个数字包括Nginx的所有连接(例如与代理服务器的连接等),而不仅仅是与客户端的连接,
# 另一个考虑因素是实际的并发连接数不能超过系统级别的最大打开文件数的限制
daemon off; # 前台运行Nginx服务用于测试、docker等环境
master_process on; # 是否开启Nginx的master-woker工作模式

events {
worker_connections 100000; # 设置单个nginx工作进程可以接受的最大并发
作为web服务器的时候最大并发数为 worker_connections * worker_processes
作为反向代理的时候为(worker_connections * worker_processes)/2
用户访问web服务器建立链接一次,web和后端服务器建立一次链接所以最大并发数要除2
配合系统参数 ulimit -n 数值,提升最大并发量
use epoll; # 使用epoll事件驱动,Nginx支持众多的事件驱动,比如select、poll、epoll,只能设置在events模块中设置
accept_mutex on; # 优化同一时刻只有一个请求而避免多个睡眠进程被唤醒,默认off ,全部唤醒的过程也成为"惊群"
multi_accept on; # Nginx服务器的每个工作进程可以同时接受多个新的网络连接,默认off
}
http {
include mime.types;
default_type application/octet-stream; # mime里文件类型不匹配,就执行默认操作-下载
sendfile on; # 作为web服务器的时候打开sendfile加快文件传输
sendfile系统调用在两个文件描述符之间直接传递数据(完全在内核中操作),从而避免了数据在内核缓冲
区和用户缓冲区之间的拷贝,操作效率很高,被称之为零拷贝
硬盘 >> kernel buffer (快速拷贝到kernelsocket buffer) >>协议栈
#tcp_nopush on; # 在开启了sendfile的情况下,合并请求后统一发送给客户端,一般默认
#tcp_nodelay off; # 在开启了keepalived模式下的连接是否启用TCP_NODELAY选项,off 合并多个请求后再发送
默认On,不延迟发送,立即发送用户相应报文
keepalive_timeout 65 60; # 设置会话保持时间,设置65,[显示60],单位是秒
gzip on; # 开启文件压缩
server {
listen 80; # 默认*:80,可写多条
charset utf-8; # #设置编码格式,默认是俄语格式
server_name www.menge.net; # 当访问此名称的时候nginx会调用当前serevr内部的配置进程匹配
可以以空格隔开写多个并支持正则表达式,如
*.menge.com ^www\d+\.menge\.com$
location / {
root html; # 相当于默认页面的目录名称,默认是相对路径,可以使用绝对路径配置。
index index.html index.htm; # 默认的页面文件名称
}
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html; # 错误页面的文件名称
location = /50x.html { # location处理对应的不同错误码的页面定义到/50x.html,这个跟对应其server中定义的目录下
root html; # 定义默认页面所在的目录
}
location ~ \.php$ { # 以http的方式转发php请求到指定web服务器
proxy_pass http://127.0.0.1;
}
location ~ \.php$ { # 以fastcgi的方式转发php请求到php处理
root html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.ht { # 拒绝web形式访问指定文件,如很多的网站都是通过.htaccess文件来改变自己的重定向等功能。
deny all;
}
location ~ /passwd.html {
deny all;
}
}
# another virtual host using mix of IP-, name-, and port-based configuration
# server { #自定义虚拟server
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm; # 指定默认网页文件,此指令由ngx_http_index_module模块提供
# }
# }
# HTTPS server
# server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
# }

#stream { # tcp代理配置,1.9版本以上支持
# ...
# } stream 服务器相关配置段
include /apps/nginx/conf.d/*.conf # 导入其他路径的配置文件,注意位置:是在http快下
}

示例:绑定work进程在cpu固定核心验证

1
2
3
4
5
[root@s2 ~]# ps axo pid,cmd,psr | grep nginx
20061 nginx: master process /apps 0
20062 nginx: worker process 0
20063 nginx: worker process 1
20097 grep --color=auto nginx 0

示例:验证进程优先级
[root@s2 ~]# watch -n1 ‘ps -axo pid,cmd,nice | grep nginx

核心配置示例

基于不同的IP、不同的端口以及不同的域名实现不同的虚拟主机,依赖于核心模块ngx_http_core_module实现

新建一个PC web站点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@s2 ~]# vim /apps/nginx/conf/nginx.conf
include /apps/nginx/conf/conf.d/*.conf; ##注意位置,写在http里server外,最好倒数第二行
[root@s2 ~]# mkdir /apps/nginx/conf/conf.d
[root@s2 ~]# cat /apps/nginx/conf/conf.d/pc.conf ## 生产中一个站点一个独立配置文件
server {
listen 80;
server_name www.menge.net;
location / {
root /data/nginx/html/pc;
}
}
[root@s2 ~]# mkdir /data/nginx/html/pc -p
[root@s2 ~]# echo "pc web" > /data/nginx/html/pc/index.html
[root@s2 ~]# nginx -s reload
[root@s2 ~]# ping www.menge.net

在win本地host文件C:\Windows\System32\drivers\etc\host添加解析: 172.18.51.17 www.menge.net
web访问www.menge.net

新建一个Mobile web站点

1
2
3
4
5
6
7
8
9
10
11
[root@s2 ~]# cat /apps/nginx/conf/conf.d/mobile.conf
server {
listen 80;
server_name mobile.menge.net;
location / {
root /data/nginx/html/mobile;
}
}
[root@s2 ~]# mkdir /data/nginx/html/mobile -p
[root@s2 ~]# echo "mobile web" >> /data/nginx/html/mobile/index.html
[root@s2 ~]# systemctl reload nginx

root与alias:

root:指定web的家目录,在定义location的时候,文件的绝对路径等于 root+location

1
2
3
4
5
6
7
8
9
10
11
12
13
server {
listen 80;
server_name www.menge.net;
location / { # 访问www.menge.net会读取/data/nginx/html/pc/index.html
root /data/nginx/html/pc; # 写相对路径的话是相对nginx安装路径
}
location /about { # 访问www.menge.net/about会读取/data/nginx/html/pc/about/index.html
root /data/nginx/html/pc; # 写相对路径的话是相对nginx安装路径
index index.html;
}
}
[root@s2 ~]# mkdir /data/nginx/html/pc/about
[root@s2 ~]# echo about > /data/nginx/html/pc/about/index.html

重载Nginx并访问测试

alias:定义路径别名,会把访问的路径重新定义到其指定的路径

1
2
3
4
5
6
7
8
server {
listen 80;
server_name www.menge.net;
location /about { # 使用alias的时候uri后面如果加了斜杠则下面的路径配置必须加斜杠,否则403
alias /data/nginx/html/pc; # 访问www.menge.net/about,会显示alias定义的 /data/nginx/html/pc/index.html
index index.html;
}
}

location的详细使用:

在没有使用正则表达式的时候,nginx会先在server中的多个location选取匹配度最高的一个uri,uri是用户请求的字符串,即域名后面的web文件路径,然后使用该location模块中的正则url和字符串,如果匹配成功就结束搜索,并使用此location处理此请求

语法规则: location [=|||^~] /uri/ { … }
= # 用于标准uri前,需要请求字串与uri精确匹配,如果匹配成功就停止向下匹配并立即处理请求
~ # 区分大小写
~
# 不区分大写
!~ # 区分大小写不匹配
!* # 不区分大小写不匹配
^
# 匹配以什么开头
$ # 匹配以什么结尾
\ # 转义字符。可以转. * ?等
* # 代表任意长度的任意字符

匹配案例 - 精确匹配:

1
2
3
4
location = /1.jpg {
root /var/www/nginx/images;
index index.html;
}

上传图片到/var/www/nginx/images,重启Nginx并访问测试
访问测试:http://www.menge.net/1.jpg

匹配案例 - URI开始:

1
2
3
4
5
6
7
8
location ^~ /images {
root /data/nginx/html;
index index.html;
}
location /images1 {
alias /data/nginx/html/pc;
index index.html;
}

重启Nginx并访问测试,实现效果是访问images和images1返回不同的结果

匹配案例 - 文件名后缀:常用于动静分离

1
2
3
4
5
6
[root@s2 ~]# mkdir /data/nginx/images1
location ~* \.gif|jpg|jpeg|bmp|png|tiff|tif|ico|wmf|js)$ {
root /data/nginx/images1;
index index.html;
}
#上传一个和images目录不一样内容的的图片1.jpg到/data/nginx/images1重启Nginx并访问测试

匹配案例 - 优先级

1
2
3
4
5
6
7
8
9
10
11
12
13
location /1.jpg {
root /var/www/nginx/images;
index index.html;
}
# location = /1.jpg {
# root /var/www/nginx/images;
# index index.html;
# }
# location ~* \.gif|jpg|jpeg|bmp|png|tiff|tif|ico|wmf|js)$ {
# root /data/nginx/images1;
# index index.html;
# }
[root@s2 ~]# mkdir /var/www/nginx/images -p

上传图片到/var/www/nginx/images并重启nginx访问测试

匹配优先级:= , ^~ , ~/~* ,/
(location =) > (location 完整路径) > (location ^~ 路径 ) > (location ,* 正则顺序) > (location 部分起始路径) > (/)

生产使用案例:

直接匹配网站根会加速Nginx访问处理:
location = / {
……;
}
静态资源配置:
location ^~ /static/ {
……;
}
或者
location ~* .(gif|jpg|jpeg|png|css|js|ico)$ {
……;
}
多应用配置
location ~* /app1 {
……;
}
location ~* /app2 {
……;
}

Nginx 四层访问控制:

访问控制基于模块ngx_http_access_module实现,可以通过匹配客户端源IP地址进行限制。(少用)
location /about {
alias /data/nginx/html/pc;
index index.html;
deny 192.168.1.1;
allow 192.168.1.0/24;
allow 10.1.1.0/16;
allow 2001:0db8::/32;
deny all; # 先允许小部分,再拒绝大部分
}

Nginx账户认证功能:(公司内部使用)

依赖模块: ngx_http_auth_basic_module

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@s2 ~]# yum install httpd-tools -y
[root@s2 ~]# htpasswd -cbm /apps/nginx/conf/.htpasswd user1 123456
Adding password for user user1
[root@s2 ~]# htpasswd -bm /apps/nginx/conf/.htpasswd user2 123456
Adding password for user user2
[root@s2 ~]# tail /apps/nginx/conf/.htpasswd
user1:$apr1$Rjm0u2Kr$VHvkAIc5OYg.3ZoaGwaGq/
user2:$apr1$nIqnxoJB$LR9W1DTJT.viDJhXa6wHv.
[root@s2 ~]# vim /apps/nginx/conf/conf.d/pc.conf
location = /login/ {
root /data/nginx/html;
index index.html;
auth_basic "login password"; # 登录对话框提示信息
auth_basic_user_file /apps/nginx/conf/.htpasswd; # 虚拟账户文件位置
}

重启Nginx并访问测试(实验中根目录的location中 等号 有问题,去掉)

自定义错误页面

1
2
3
4
5
6
7
8
9
10
[root@s2 ~]# vim /apps/nginx/conf/conf.d/pc.conf
listen 80;
server_name www.menge.net;
error_page 500 502 503 504 404 /error.html; # 出现上面错误码后跳转到 家目录下即/apps/nginx/html/error.html
location = /error.html {
root html; # 相对/app/nginx/
# root /data/nginx/html/error_page # 以后备份可以不备份此日志
}
[root@s2 ~]# echo "eror_page" > /data/nginx/html/error_page/index.html
[root@s2 ~]# chown nginx.nginx /var/log/nginx/ /data/ -R

重启nginx并访问不存在的页面进行测试

自定义访问日志:(作用于server、location)

1
2
3
4
5
6
7
8
9
10
11
[root@s2 ~]# mkdir /data/nginx/logs
[root@s2 ~]# vim /apps/nginx/conf/conf.d/pc.conf
server {
server_name www.menge.net;
access_log /data/nginx/logs/www_menge_net_access.log;
error_log /data/nginx/logs/www_menge_net_error.log;
location /login {
root html;
access_log /data/nginx/logs/www-menge-net_login.log; # 经验:名字区分不同日志
}
}

重启nginx并访问不存在的页面进行测试并验证是在指定目录生成新的日志文件

监测文件是否存在

try_files会按顺序检查文件是否存在,返回第一个找到的文件或文件夹(结尾加斜线表示为文件夹),如果所有文件或文件夹都找不到,会进行一个内部重定向到最后一个参数。只有最后一个参数可以引起一个内部重定向,之前的参数只设置内部URI的指向。最后一个参数是回退URI且必须存在,否则会出现内部500错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
location /about {
root /data/nginx/html/pc;
index index.html;
#try_files $uri /about/default.html; # $uri是用户请求的页面
#try_files $uri $uri/index.html $uri.html /about/default.html; # 重定向到其他页面, 可实现访问不存在的页面跳转到首页
try_files $uri $uri/index.html $uri.html =489; # 返回状态码
}
[root@s2 ~]# echo "default" >> /data/nginx/html/pc/about/default.html
重启nginx并测试,当访问到http://www.menge.net/about/xx.html等不存在的uri会显示default,如果是自定义的状态码则会显示在返回数据的状态码中,如:
[root@s2 about]# curl --head http://www.menge.net/about/xx.html
HTTP/1.1 489 # 489就是自定义的状态返回码
Server: nginx
Date: Thu, 21 Feb 2019 00:11:40 GMT
Content-Length: 0
Connection: keep-alive
Keep-Alive: timeout=65

长连接配置

会话保持时间:用户和服务器建立连接后客户端分配keep-alive链接超时时间,服务器将在这个超时时间过后关闭链接,我们将它设置高些可以让ngnix持续工作的时间更长,1.8.1默认为65秒,一般不超过120秒

1
2
3
4
5
6
keepalive_requests 100;		# 在一次长连接上所允许请求的资源的最大数量,默认为100
keepalive_timeout 65 60; # 设定保持连接超时时长,0表示禁止长连接,默认为75s,通常配置在http字段作为站点全局配置
返回客户端的会话保持时间为60s,单次长连接累计请求达到指定次数请求或65秒就会被断开
60为发送给客户端应答报文头部中显示的超时时间, 如不设置客户端将不显示超时时间
浏览器收到的服务器返回的报文示例:Keep-Alive:timeout=60
如果设置为0表示关闭会话保持功能,浏览器收到的服务器返回的报文将如下显示:Connection:close

使用命令测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[root@s3 apps]# telnet www.menge.net 80
Trying 172.18.200.102...
Connected to www.menge.net.
Escape character is '^]'.
GET / HTTP/1.1
HOST: www.menge.net
Response Headers(响应头信息):
HTTP/1.1 200 OK
Server: nginx/1.14.2
Date: Thu, 14 Mar 2019 17:23:46 GMT
Content-Type: text/html
Content-Length: 7
Last-Modified: Thu, 14 Mar 2019 14:54:50 GMT
Connection: keep-alive
Keep-Alive: timeout=60
ETag: "5c8a6b3a-7"
Accept-Ranges: bytes
#页面内容
pc web

作为下载服务器配置:

1
2
3
4
5
6
7
8
9
10
11
[root@s2 about]# mkdir /data/nginx/html/pc/download		# download不需要index.html文件
[root@s2 about]# vim /apps/nginx/conf/conf.d/pc.conf
location /download {
root /data/nginx/html/pc;
autoindex on; # 自动索引功能
autoindex_exact_size on; # 计算文件确切大小(单位bytes),off只显示大概大小(单位kb、mb、gb)
autoindex_localtime on; # 显示本机时间而非GMT(格林威治)时间
limit_rate 10k; # 限制响应给客户端的传输速率,单位是bytes/second,默认值0表示无限制
}
[root@s2 pc]# cp /root/anaconda-ks.cfg /data/nginx/html/pc/download/
[root@s2 pc]# chown -R nginx.nginx /data/nginx/; # 会有权限问题

重启Nginx并访问测试下载页面

作为上传服务器

1
2
3
4
5
6
7
8
9
location /download {
root /data/nginx/html/upload;
client_max_body_size 1m; # 设置允许客户端上传单个文件的最大值,默认值为1m
client_body_buffer_size 16k; 用于接收每个客户端请求报文的body部分的缓冲区大小;默认16k;超出此大小时,其将被
暂存到磁盘上的由下面client_body_temp_path指令所定义的位置
client_body_temp_path path [level1 [level2 [level3]]]; # 设定存储客户端请求报文的body部分的临时存储路径及子目录结构和数量,目录名为16进制的数字,使用hash之后的值从后往前截取1位、2位、2位作为文件名:
}
[root@s3 ~]# md5sum /data/nginx/html/pc/index.html
95f6f65f498c74938064851b1bb 96 3d 4 /data/nginx/html/pc/index.html

1级目录占1位16进制,即2^4=16个目录 0-f
2级目录占2位16进制,即2^8=256个目录 00-ff
3级目录占2位16进制,即2^8=256个目录 00-ff
配置示例:
client_max_body_size 10m;
client_body_buffer_size 16k;
client_body_temp_path /apps/nginx/temp 1 2 2; # reload 后Nginx会自动创建temp目录

其他配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
keepalive_disable none | browser ...;		# 对哪种浏览器禁用长连接

send_timeout TIME; # 向客户端发送响应报文的超时时长,此处指两次写操作之间的间隔时长,而非整个响应过程的传输时长

limit_except method ... { ... } # 仅用于location,限制客户端使用除了指定的请求方法之外的其它方法
method: GET, HEAD, POST, PUT, DELETE,MKCOL, COPY, MOVE, OPTIONS, PROPFIND,PROPPATCH, LOCK, UNLOCK, PATCH
limit_except GET {
allow 192.168.0.0/24;
deny all;
}
# 除了GET和HEAD(默认允许) 之外其它方法仅允许192.168.1.0/24网段主机使用
[root@s2 about]# mkdir /data/nginx/html/pc/upload
[root@s2 about]# echo "upload" > /data/nginx/html/pc/upload/index.html
[root@s2 about]# vim /apps/nginx/conf/conf.d/pc.conf
location /upload {
root /data/nginx/html/pc;
index index.html;
limit_except GET { # 只允许get
allow 192.168.0.0/24;
allow 192.168.7.102;
deny all;
}
}

# 重启Nginx并进行测试上传文件
[root@s2 pc]# systemctl restart nginx
[root@s2 pc]# curl -XPUT /etc/issue http://www.menge.net/about
curl: (3) <url> malformed
<html>
<head><title>405 Not Allowed</title></head> # 未支持上传功能
<body bgcolor="white">
<center><h1>405 Not Allowed</h1></center>
<hr><center>nginx</center>
</body>
</html>
[root@s1 ~]# curl -XPUT /etc/issue http://www.menge.net/upload
curl: (3) <url> malformed
<html>
<head><title>403 Forbidden</title></head> # 拒绝上传
<body bgcolor="white">
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx</center>
</body>
</html>

aio on | off # 是否启用asynchronous file I/O(AIO)功能,linux 2.6以上内核提供以下几个系统调用来支持aio:
1、SYS_io_setup:建立aio 的context
2、SYS_io_submit: 提交I/O操作请求
3、SYS_io_getevents:获取已完成的I/O事件
4、SYS_io_cancel:取消I/O操作请求
5、SYS_io_destroy:毁销aio的context

directio size | off; # 启用直接I/O,默认为关闭
当文件大于等于给定大小时,例如directio 4m,同步(直接)写磁盘,而非写缓存

open_file_cache off;
open_file_cache max=N [inactive=time];
max=N: 可缓存的缓存项上限数量;达到上限后会使用LRU(Least recently used,最近最少使用)算法实现管理
inactive=time: 缓存项的非活动时长,在此处指定的时长内未被命中的或命中的次数少于open_file_cache_min_uses指令
所指定的次数的缓存项即为非活动项,将被删除
缓存优点:在一定时间内加速访问
缓存缺点:缓存过期问题,内容改变缓存没有变,用户不能及时访问实时信息
nginx可以缓存以下三种信息:
(1) 文件元数据:文件的描述符、文件大小和最近一次的修改时间
(2) 打开的目录结构
(3) 没有找到的或者没有权限访问的文件的相关信息

open_file_cache_errors on | off; # 是否缓存查找时发生错误的文件一类的信息,默认值为off

open_file_cache_min_uses 1; # open_file_cache指令的inactive参数指定的时长内,至少被命中此处指定的次数方可被归
类为活动项,默认值为1

open_file_cache_valid 60s; # 缓存项有效性的检查验证频率,默认值为60s
open_file_cache max=10000 inactive=60s;
open_file_cache_min_uses 5; # 60s内缓存次数低于5此就删除
open_file_cache_errors on;

server_tokens off; # 隐藏Nginx server版本,作用于 http server location,放主配置文件,全局生效

Nginx 高级配置

ginx 状态页

基于nginx模块ngx_http_auth_basic_module实现,在编译安装nginx的时候需要添加编译参数–withhttp_stub_status_module,否则配置完成之后监测会是提示语法错误

1
2
3
4
5
6
location /nginx_status {
stub_status;
allow 192.168.0.0/16;
allow 127.0.0.1;
deny all;
}

输出信息示例:
Active connections: 291
server accepts handled requests
16630948 16630948 31070465
Reading: 6 Writing: 179 Waiting: 106
Active connections: 当前处于活动状态的客户端连接数,包括连接等待空闲连接数
accepts: Nginx自启动后已经接受的客户端请求的总数
handled: Nginx自启动后已经处理完成的客户端请求的总数,通常等于accepts,除非有因worker_connections限制等被拒绝的连接
requests:Nginx自启动后客户端发来的总的请求数
Reading:当前状态,正在读取客户端请求报文首部的连接的连接数
Writing:当前状态,正在向客户端发送响应报文过程中的连接数
Waiting:当前状态,正在等待客户端发出请求的空闲连接数,开启 keep-alive的情况下,这个值等于active – (reading+writing)

Nginx 第三方模块

第三模块是对nginx 的功能扩展,第三方模块需要在编译安装Nginx 的时候使用参数–add-module=PATH指定路径添加,有的模块是由公司的开发人员针对业务需求定制开发的,有的模块是开源爱好者开发好之后上传到github进行开源的模块,nginx支持第三方模块需要从源码重新编译支持,比如开源的echo模块 https://github.com/openresty/echo-nginx-module:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
[root@s2 pc]# vim /apps/nginx/conf/conf.d/pc.conf
location /main {
index index.html;
default_type text/html; # 使访问时不下载而是打印
echo "hello world,main-->"; echo没有集成在mime默认支持的文件类型里,访问时会执行下载添加此行解决
echo_reset_timer;
echo_location /sub1;
echo_location /sub2;
echo "took $echo_timer_elapsed sec for total.";
}
location /sub1 {
echo_sleep 1;
echo sub1;
}
location /sub2 {
echo_sleep 1;
echo sub2;
}
[root@s2 pc]# /apps/nginx/sbin/nginx -t
nginx: [emerg] unknown directive "echo_reset_timer" in
/apps/nginx/conf/conf.d/pc.conf:86
nginx: configuration file /apps/nginx/conf/nginx.conf test failed

#解决以上报错问题(注释掉配置文件中的echo)
[root@s2 src]# ./configure --help|grep add # 查找添加第三方模块参数 --add-module=PATH
[root@s2 src]# yum install git -y
[root@s2 src]# git clone https://github.com/openresty/echo-nginx-module.git
[root@s2 src]# cd nginx-1.12.2/
[root@s2 src]# ./configure \
--prefix=/apps/nginx \
--user=nginx --group=nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_stub_status_module \
--with-http_gzip_static_module \
--with-pcre \
--with-stream \
--with-stream_ssl_module \
--with-stream_realip_module \
--with-http_perl_module \
--add-module=/usr/local/src/echo-nginx-module # 下载的模块位置
[root@s2 src]# make
[root@s2 pc]# systemctl stop nginx
[root@s2 src]# make install
[root@s2 pc]# vim /apps/nginx/conf/conf.d/pc.conf # 删掉注释
[root@s2 pc]# /apps/nginx/sbin/nginx -t
[root@s2 pc]# systemctl restart nginx
[root@s2 pc]# curl http://www.menge.net/main
hello world,main-->
sub1
sub2
took 2.010 sec for total.

Nginx 变量使用

nginx的变量可以在配置文件中引用,作为功能判断或者日志等场景使用,变量可以分为内置变量和自定义变量,内置变量是由nginx模块自带,通过变量可以获取到众多的与客户端访问相关的值。

内置变量:

$remote_addr; # 存放了客户端的地址,注意是客户端的公网IP,也就是一家人访问一个网站,则会显示为路由器的公网IP
$args; # 变量中存放了URL中的指令
例如http://www.menge.net/main/index.do?id=20190221&partner=search中的id=20190221&partner=search
$document_root; # 保存了针对当前资源的请求的系统根目录
就是location里的root,不指定root会跳到主配置的/apps/nginx/html里
$document_uri; # 保存了当前请求中不包含指令的URI,注意是不包含请求的指令
http://www.menge.net/main/index.do?id=20190221&partner=search会被定义为/main/index.do
$host; # 存放了请求的host名称。访问jd时在request headers里Host:www.jingdong.com,用来统计此域名的访问量
$http_user_agent; # 客户端浏览器的详细信息,默认在main log中的格式项
$http_cookie; # 客户端的cookie信息。
limit_rate 10240; echo $limit_rate; # 如果nginx服务器使用limit_rate配置了显示网络速率,则会显示,如果没有设置, 则显示0
$remote_port; # 客户端请求Nginx服务器时随机打开的端口,这是每个客户端自己的端口
$remote_user; # 已经经过Auth Basic Module验证的用户名
$request_body_file; # 做反向代理时发给后端服务器的本地资源的名称
$request_method; # 请求资源的方式,GET/PUT/DELETE等,默认是GET
$request_filename; # 当前请求的资源文件的路径名称,由root或alias指令与URI请求生成的文件绝对路径
如/apps/nginx/html/main/index.html
$request_uri; # 包含请求参数的原始URI,不包含主机名,如:/main/index.do?id=20190221&partner=search
$scheme; # 请求的协议,如ftp,https,http等。
$server_protocol; # 保存了客户端请求资源使用的协议的版本,如HTTP/1.0,HTTP/1.1,HTTP/2.0等。
$server_addr; # 保存了服务器的IP地址。
$server_name; # 请求的服务器的主机名。
$server_port; # 请求的服务器的端口号。

自定义变量

假如需要自定义变量名称和值,Syntax: set $variable value
set $name menge
set $m_port
echo $menge:$m_port

Nginx 自定义访问日志

访问日志是记录客户端的具体请求内容信息,全局配置模块中的error_log是记录nginx服务器运行时的日志保存路径和记录日志的level,因此有着本质的区别,而且Nginx的错误日志一般只有一个,但是访问日志可以在不同server中定义多个,定义一个日志需要使用access_log指定日志的保存路径,使用log_format指定日志的格式,格式中定义要保存的具体日志内容。

自定义默认格式日志

自定义日志注意include的位置,放在http里表示所有inculde目录里配置文件都是在http里写的
如果是要保留日志的源格式,只是添加相应的日志内容,则配置如下:

1
2
3
log_format  nginx_format1  '$remote_addr - $remote_user [$time_local] "$request" '  '$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"' '$server_name:$server_port';
access_log logs/access.log nginx_format1;

重启nginx并访问测试日志格式
==> /apps/nginx/logs/access.log
192.168.0.1 - - [22/Feb/2019:08:44:14 +0800] “GET /favicon.ico HTTP/1.1” 404 162 “-“ “Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0” “-“www.menge.net:80

自定义json格式日志:

Nginx 的默认访问日志记录内容相对比较单一,默认的格式也不方便后期做日志统计分析,生产环境中通常将nginx日志转换为json日志,然后配合使用ELK做日志收集-统计-分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
log_format access_json '{"@timestamp":"$time_iso8601",'
'"host":"$server_addr",'
'"clientip":"$remote_addr",'
'"size":$body_bytes_sent,'
'"responsetime":$request_time,'
'"upstreamtime":"$upstream_response_time",'
'"upstreamhost":"$upstream_addr",'
'"http_host":"$host",'
'"uri":"$uri",'
'"domain":"$host",'
'"xff":"$http_x_forwarded_for",'
'"referer":"$http_referer",'
'"tcp_xff":"$proxy_protocol_addr",'
'"http_user_agent":"$http_user_agent",'
'"status":"$status"}';
access_log /apps/nginx/logs/access_json.log access_json;

重启Nginx并访问测试日志格式
{“@timestamp”:”2019-02-22T08:55:32+08:00”,”host”:”192.168.7.102”,”clientip”:”192.168.0.1”,”size”:162,”responsetime”:0.000,”upstreamtime”:”-“,”upstreamhost”:”-“,”http_host”:”www.menge.net","uri":"/favicon.ico","domain":"www.menge.net","xff":"-","referer":"-","tcp_xff":"","http_user_agent":"Mozilla/5.0 (Windows NT 6.1;Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0”,”status”:”404”}

json格式的日志访问统计:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/bin/env python
#coding:utf-8
#Author:Zhang ShiJie
status_200= []
status_404= []
with open("access_json.log") as f:
for line in f.readlines():
line = eval(line)
if line.get("status") == "200":
status_200.append(line.get)
elif line.get("status") == "404":
status_404.append(line.get)
else:
print("状态码 ERROR")
f.close()
print "状态码200的有--:",len(status_200)
print "状态码404的有--:",len(status_404)

#保存日志文件到指定路径并进测试:
[root@s2 ~]# python nginx_json.py
状态码200的有--: 1910
状态码404的有--: 13

Nginx 压缩功能

Nginx支持对指定类型的文件进行压缩然后再传输给客户端,而且压缩还可以设置压缩比例,压缩后的文件大小将比源文件显著变小,这样有助于降低出口带宽的利用率,降低企业的IT支出,不过会占用相应的CPU资源
依赖于模块ngx_http_gzip_module
官方文档: https://nginx.org/en/docs/http/ngx_http_gzip_module.html, 配置指令如下:

主配置文件的http里

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
gzip on | off;		# 启用或禁用gzip压缩,默认关闭
gzip_comp_level level; # 压缩比由低到高从1到9,默认为1
gzip_disable "MSIE [1-6]\."; #禁用IE6 gzip功能
gzip_min_length 1k; # gzip压缩的最小文件,小于设置值的文件将不会压缩
gzip_http_version 1.0 | 1.1; # 启用压缩功能时,协议的最小版本,默认HTTP/1.1
gzip_buffers number size; # 指定Nginx服务需要向服务器申请的缓存空间的 个数 * 大小,默认32 4k | 16 8k;
gzip_types mime-type ...; # 指明仅对哪些类型的资源执行压缩操作
默认为gzip_types text/html,不用显示指定,否则出错
gzip_vary on | off; # 如果启用压缩,是否在响应报文首部插入“Vary: Accept-Encoding”

[root@s2 pc]# cp /apps/nginx/logs/access.log /data/nginx/html/pc/test.html
[root@s2 pc]# echo "test1" > /data/nginx/html/pc/test1.html #小于1k的文件测试是否会压缩
[root@s2 pc]# vim /apps/nginx/conf/nginx.conf
gzip on;
gzip_comp_level 5;
gzip_min_length 1k;
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
gzip_vary on;

重启Nginx并访问测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@s2 pc]# curl --head --compressed http://www.menge.net
HTTP/1.1 200 OK
Server: nginx
Date: Thu, 21 Feb 2019 13:06:18 GMT
Content-Type: text/html
Content-Length: 7
Last-Modified: Tue, 19 Feb 2019 04:09:32 GMT
Connection: keep-alive
Keep-Alive: timeout=65
ETag: "5c6b817c-7"
Accept-Ranges: bytes
[root@s2 ~]# curl --head --compressed http://www.menge.net/test.html
HTTP/1.1 200 OK
Server: nginx
Date: Fri, 22 Feb 2019 01:52:23 GMT
Content-Type: text/html
Last-Modified: Thu, 21 Feb 2019 10:31:18 GMT
Connection: keep-alive
Keep-Alive: timeout=65
Vary: Accept-Encoding
ETag: W/"5c6e7df6-171109"
Content-Encoding: gzip

https

Web网站的登录页面都是使用https加密传输的,加密数据以保障数据的安全,HTTPS能够加密信息,以免敏感信息被第三方获取,所以很多银行网站或电子邮箱等等安全级别较高的服务都会采用HTTPS协议,HTTPS其实是有两部分组成:HTTP + SSL / TLS,也就是在HTTP上又加了一层处理加密信息的模块。服务端和客户端的信息传输都会通过TLS进行加密,所以传输的数据都是加密后的数据

https 实现过程如下:
1.客户端发起HTTPS请求:
客户端访问某个web端的https地址,一般都是443端口
2.服务端的配置:
采用https协议的服务器必须要有一套证书,可以通过一些组织申请,也可以自己制作,目前国内很多网站都自己做的,当你访问一个网站的时候提示证书不可信任就表示证书是自己做的,证书就是一个公钥和私钥匙,就像一把锁和钥匙,正常情况下只有你的钥匙可以打开你的锁,你可以把这个送给别人让他锁住一个箱子,里面放满了钱或秘密,别人不知道里面放了什么而且别人也打不开,只有你的钥匙是可以打开的。
3.传送证书:
服务端给客户端传递证书,其实就是公钥,里面包含了很多信息,例如证书得到颁发机构、过期时间等等。
4.客户端解析证书:
这部分工作是由客户端完成的,首先回验证公钥的有效性,比如颁发机构、过期时间等等,如果发现异常则会弹出一个警告框提示证书可能存在问题,如果证书没有问题就生成一个随机值,然后用证书对该随机值进行加密,就像2步骤所说把随机值锁起来,不让别人看到。
5.传送4步骤的加密数据:
就是将用证书加密后的随机值传递给服务器,目的就是为了让服务器得到这个随机值,以后客户端和服务端的通信就可以通过这个随机值进行加密解密了
6.服务端解密信息:
服务端用私钥解密5步骤加密后的随机值之后,得到了客户端传过来的随机值(私钥),然后把内容通过该值进行对称加密,对称加密就是将信息和私钥通过某种算法混合在一起,这样除非你知道私钥,不然是无法获取其内部的内容,而正好客户端和服务端都知道这个私钥,所以只要机密算法够复杂就可以保证数据的安全性。
7.传输加密后的信息:
服务端将用私钥加密后的数据传递给客户端,在客户端可以被还原出原数据内容。
8.客户端解密信息:
客户端用之前生成的私钥获解密服务端传递过来的数据,由于数据一直是加密得,因此即使第三方获取到数据也无法知道其详细内容

ssl 配置参数

官方文档: https://nginx.org/en/docs/http/ngx_http_ssl_module.html
nginx 的https 功能基于模块ngx_http_ssl_module实现,因此如果是编译安装的nginx要使用参数ngx_http_ssl_module开启ssl功能,但是作为nginx的核心功能,yum安装的nginx默认就是开启的,编译安装的nginx需要指定编译参数–with-http_ssl_module开启,配置参数如下:

ssl on | off;
#为指定的虚拟主机配置是否启用ssl功能,此功能在1.15.0废弃,使用listen [ssl]替代。

ssl_certificate /path/to/file;
#当前虚拟主机使用使用的公钥文件,一般是crt文件

ssl_certificate_key /path/to/file;
#当前虚拟主机使用的私钥文件,一般是key文件

ssl_protocols [SSLv2] [SSLv3] [TLSv1] [TLSv1.1] [TLSv1.2];
#支持ssl协议版本,早期为ssl现在是TSL,默认为后三个

ssl_session_cache off | none | [builtin[:size]] [shared:name:size];
#配置ssl缓存
off: 关闭缓存
none: 通知客户端支持ssl session cache,但实际不支持,默认
builtin[:size]:使用OpenSSL内建缓存,为每worker进程私有
[shared:name:size]:在各worker之间使用一个共享的缓存,需要定义一个缓存名称和缓存空间大小,一兆可以存储4000个会话信息,多个虚拟主机可以使用相同的缓存名称

ssl_session_timeout time;
#客户端连接可以复用ssl session cache中缓存的有效时长,默认5m

自签名 证书

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#自签名CA证书
[root@s2 ~]# mkdir /apps/nginx/ certs
[root@s2 nginx]# cd /apps/nginx/ certs
[root@s2 nginx]# openssl req -newkey rsa:4096 -nodes -sha256 -keyout ca.key -x509 -days 3650 -out ca.crt
Generating a 4096 bit RSA private key
.................++
.....
Country Name (2 letter code) [XX]:CN #国家代码 # 书写错误使用ctrl+backspace
State or Province Name (full name) []:BeiJing #省份
Locality Name (eg, city) [Default City]:Beijing #城市名称
Organization Name (eg, company) [Default Company Ltd]:menge.Ltd #公司名称
Organizational Unit Name (eg, section) []:menge #部门
Common Name (eg, your name or your server's hostname) []:menge.ca #通用名称
Email Address []:425602003@qq.com #邮箱

#自制key和csr文件
[root@s2 certs]# openssl req -newkey rsa:4096 -nodes -sha256 -keyout www.menge.net.key -out www.menge.net.csr
Generating a 4096 bit RSA private key
........................................................................++
......
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:BeiJing
Locality Name (eg, city) [Default City]:BeiJing
Organization Name (eg, company) [Default Company Ltd]:menge.net
Organizational Unit Name (eg, section) []:menge.net
Common Name (eg, your name or your server's hostname) []:www.menge.net
Email Address []:425602003@qq.com
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []: # 密码不要
An optional company name []: # 可选信息,不写

[root@s2 certs]# ll
total 16
-rw-r--r-- 1 root root 2118 Feb 22 12:10 ca.crt
-rw-r--r-- 1 root root 3272 Feb 22 12:10 ca.key
-rw-r--r-- 1 root root 1760 Feb 22 12:18 www.menge.net.csr
-rw-r--r-- 1 root root 3272 Feb 22 12:18 www.menge.net.key

#签发证书
[root@s2 certs]# openssl x509 -req -days 3650 -in www.menge.net.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out www.menge.net.crt
Signature ok
subject=/C=CN/ST=BeiJing/L=BeiJing/O=menge.net/OU=menge.net/CN=www.menge.net/emailAddress=425602003@qq.com
Getting CA Private Key

#验证证书内容
[root@s2 certs]# openssl x509 -in www.menge.net.crt -noout -text
Certificate:
Data:
Version: 1 (0x0)
Serial Number:
bb:76:ea:fe:f4:04:ac:06
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=CN, ST=BeiJing, L=Beijing, O=menge.Ltd, OU=menge,CN=menge.ca/emailAddress=2973707860@qq.com
Validity
Not Before: Feb 22 06:14:03 2019 GMT
Not After : Feb 22 06:14:03 2020 GMT
Subject: C=CN, ST=BeiJing, L=BeiJing, O=menge.net, OU=menge.net,CN=www.menge.net/emailAddress=425602003@qq.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (4096 bit)
Nginx证书配置:
1
2
3
4
5
6
7
8
9
10
server{
listen 80;
server_name www.menge.net;
listen 443 ssl;
ssl_certificate /apps/nginx/certs/www.menge.net.crt;
ssl_certificate_key /apps/nginx/certs/www.menge.net.key;
ssl_session_cache shared:sslcache:20m;
ssl_session_timeout 10m;
}
#重启Nginx并访问验证

实现多域名HTTPS

Nginx支持基于单个IP实现多域名的功能,并且还支持单IP多域名的基础之上实现HTTPS,其实是基于Nginx的SNI(Server Name Indication)功能实现,SNI是为了解决一个Nginx服务器内使用一个IP绑定多个域名和证书的功能,其具体功能是客户端在连接到服务器建立SSL链接之前先发送要访问站点的域名(Hostname),这样服务器再根据这个域名返回给客户端一个合适的证书

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#制作key和csr文件
[root@s2 certs]# openssl req -newkey rsa:4096 -nodes -sha256 -keyout mobile.menge.net.key -out mobile.menge.net.csr
Generating a 4096 bit RSA private key
..........
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:BeiJing
Locality Name (eg, city) [Default City]:BeiJing
Organization Name (eg, company) [Default Company Ltd]:menge
Organizational Unit Name (eg, section) []:menge
Common Name (eg, your name or your server's hostname) []:mobile.menge.net
Email Address []:425602003@qq.com
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

#移动端签发证书
[root@s2 certs]# openssl x509 -req -days 3650 -in mobile.menge.net.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out mobile.menge.net.crt
Signature ok
subject=/C=CN/ST=BeiJing/L=BeiJing/O=menge/OU=menge/CN=mobile.menge.net/emailAdd
ress=2973707860@qq.com
Getting CA Private Key

#验证证书内容
[root@s2 certs]# openssl x509 -in mobile.menge.net.crt -noout -text
Certificate:
Data:
Version: 1 (0x0)
Serial Number:
bb:76:ea:fe:f4:04:ac:07
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=CN, ST=BeiJing, L=Beijing, O=menge.Ltd, OU=menge,
CN=menge.ca/emailAddress=425602003@qq.com
Validity
Not Before: Feb 22 13:50:43 2019 GMT
Not After : Feb 19 13:50:43 2029 GMT
Subject: C=CN, ST=BeiJing, L=BeiJing, O=menge, OU=menge,
CN=mobile.menge.net/emailAddress=425602003@qq.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (4096 bit)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#Nginx 配置
[root@s2 certs]# cat /apps/nginx/conf/conf.d/mobile.conf
server {
listen 80
default_server;
server_name mobile.menge.net;
rewrite ^(.*)$ https://$server_name$1 permanent;
}
server {
listen 443 ssl;
server_name mobile.menge.net;
ssl_certificate /apps/nginx/certs/mobile.menge.net.crt;
ssl_certificate_key /apps/nginx/certs/mobile.menge.net.key;
ssl_session_cache shared:sslcache:20m;
ssl_session_timeout 10m;
location / {
root "/data/nginx/html/mobile";
}
location /mobile_status {
stub_status;
#allow 172.16.0.0/16;
#deny all;
}
}

关于favicon.ico:网页选项卡的图标

favicon.ico 文件是浏览器收藏网址时显示的图标,当客户端使用浏览器问页面时,浏览器会自己主动发起请求获取页面的favicon.ico文件,但是当浏览器请求的favicon.ico文件不存在时,服务器会记录404日志,而且浏览器也会显示404报错,解决办法:

一:服务器不记录访问日志:

1
2
3
4
#location = /favicon.ico {
#log_not_found off;
#access_log off;
#}

二:将图标保存到指定目录访问: # 生产中要把图片单独存放一个文件夹,实验中放在pc/images下找不到

1
2
3
4
5
6
7
#location ~ ^/favicon\.ico$ {
location = /favicon.ico {
#root /data/nginx/html/pc/images;
root /data/nginx/html/images;
}
[root@s2 certs]# chown nginx.nginx /data/nginx/html/ -R
[root@s2 certs]# nginx -s reload

Nginx Rewrite相关功能

Nginx服务器利用ngx_http_rewrite_module 模块解析和处理rewrite请求,所以说此功能依靠 PCRE(perlcompatible regularexpression),因此编译之前要安装PCRE库,rewrite是nginx服务器的重要功能之一,用于实现URL的重写,URL的重写是非常有用的功能,比如它可以在我们改变网站结构之后,不需要客户端修改原来的书签,也无需其他网站修改我们的链接,就可以设置为访问,另外还可以在一定程度上提高网站的安全性

ngx_http_rewrite_module模块指令

文档:https://nginx.org/en/docs/http/ngx_http_rewrite_module.html

if指令:

用于条件匹配判断,并根据条件判断结果选择不同的Nginx配置,可以配置在server或location块中进行配置,Nginx的if语法仅能使用if做单次判断,不支持使用if else或者if elif这样的多重判断,用法如下:
if (条件匹配) {
action
}

location /main {
index index.html;
if ( $scheme = http ){ # 不加判断只写rewrite,当访问https时会进入跳转死循环(页面不能访问)
echo “if—–> $scheme”;
rewrite / https://www.jd.com permanent;
}
}

使用正则表达式对变量进行匹配,匹配成功时if指令认为条件为true,否则认为false,变量与表达式之间使用以下符号链接:

=:         # 比较变量和字符串是否相等,相等时if指令认为该条件为true,反之为false。
!=:         # 比较变量和字符串是否不相等,不相等时if指令认为条件为true,反之为false。
~:         # 表示在匹配过程中区分大小写字符,(可以通过正则表达式匹配),满足匹配条件为真,不满足为假。
~*:         # 表示在匹配过程中不区分大小写字符,(可以通过正则表达式匹配),满足匹配条件为真,不满足问假。
!~:        # 区分大小写不匹配,不满足为真,满足为假,不满足为真。
!~*:        # 为不区分大小写不匹配,满足为假,不满足为真。
-f 和 ! -f:        # 判断请求的文件是否存在和是否不存在
-d 和 ! -d:         # 判断请求的目录是否存在和是否不存在。
-x 和 ! -x:     # 判断文件是否可执行和是否不可执行。
-e 和 ! -e:        # 判断请求的文件或目录是否存在和是否不存在(包括文件,目录,软链接)

注: 如果$变量的值为空字符串或是以0开头的任意字符串,则if指令认为该条件为false,其他条件为true

set指令:

指定key并给其定义一个变量,变量可以调用Nginx内置变量赋值给key,另外set定义格式为set $key $value,及无论是key还是value都要加$符号。

1
2
3
4
5
6
7
8
9
location /main {
root /data/nginx/html/pc;
index index.html;
default_type text/html;
set $name menge;
echo $name;
set $my_port $server_port;
echo $my_port;
}

break指令:

用于中断当前相同作用域(location)中的其他Nginx配置,与该指令处于同一作用域的Nginx配置中,位于它前面的配置生效,位于后面的指令配置就不再生效了,Nginx服务器在根据配置处理请求的过程中遇到该指令的时候,回到上一层作用域继续向下读取配置,该指令可以在server块和location块以及if块中使用,使用语法如下:

1
2
3
4
5
6
7
8
9
10
location /main {
root /data/nginx/html/pc;
index index.html;
default_type text/html;
set $name menge;
echo $name;
#break;
set $my_port $server_port;
echo $my_port;
}

return指令

从nginx版本0.8.2开始支持,return用于完成对请求的处理,并直接向客户端返回响应状态码,比如其可以指定重定向URL(对于特殊重定向状态码,301/302等) 或者是指定提示文本内容(对于特殊状态码403/500等),处于此指令后的所有配置都将不被执行,return可以在server、if和location块进行配置,用法如下:
return code; #返回给客户端指定的HTTP状态码
return code (text); #返回给客户端的状态码及响应体内容,可以调用变量
return code URL; #返回给客户端的URL地址

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
location /main {
root /data/nginx/html/pc;
default_type text/html;
index index.html;
if ( $scheme = http ){
#return 666; #返回状态码
#return 666 "not allow http"; # 页面显示not allow http
#return 301 http://www.baidu.com; # 301永久重定向,会直接跳转到baidu,缓存信息
302临时重定向 不会缓存
return 500 "service error";
echo "if-----> $scheme"; #return后面的将不再执行
}
if ( $scheme = https ){
echo "if ----> $scheme";
}

rewrite_log指令:

设置是否开启记录ngx_http_rewrite_module模块日志记录到error_log日志文件当中,可以配置在http、server、location或if当中,需要日志级别为notice

1
2
3
4
5
6
7
8
9
10
11
12
13
location /main {
index index.html;
default_type text/html;
set $name menge;
echo $name;
rewrite_log on;
break;
set $my_port $server_port;
echo $my_port;
}
#重启nginx,访问并验证error_log:
[root@s2 ~]# tail -f /apps/nginx/logs/error.log
2019/02/27 15:10:02 [warn] 5815#0: *3 using uninitialized "my_port" variable,client: 192.168.0.1, server: www.menge.net, request: "GET /main HTTP/1.1", host:"www.menge.net"

rewrite指令:

通过正则表达式的匹配来改变URI,可以同时存在一个或多个指令,按照顺序依次对URI进行匹配,rewrite主要是针对用户请求的URL或者是URI做具体处理

URI(universal resource identifier):通用资源标识符,标识一个资源的路径,可以不带协议。
URL(uniform resource location): 统一资源定位符,是用于在Internet中描述资源的字符串,是URI的子集,主要包括传世协议(scheme)、主机(IP、端口号或者域名)和资源具体地址(目录和文件名)等三部分,一般格式为 scheme://主机名[:端口号][/资源路径],
如:http://www.a.com:8080/path/file/index.html 就是一个URL路径,URL必须带访问协议
每个URL都是一个URI,但是URI不都是URL,例如:
http://example.org/absolute/URI/with/absolute/path/to/resource.txt #URI/URL
ftp://example.org/resource.txt #URI/URL
/relative/URI/with/absolute/path/to/resource.txt #URI

rewrite的官方介绍地址:https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite
rewrite可以配置在server、location、if,其具体使用方式为:rewrite regex replacement [flag];

rewrite将用户请求的URI基于regex所描述的模式进行检查,匹配到时将其替换为replacement指定的新的URI 注意:如果在同一级配置块中存在多个rewrite规则,那么会自下而下逐个检查;被某条件规则替换完成后,会重新一轮的替换检查,隐含有循环机制,但不超过10次;如果超过,提示500响应码,[flag]所表示的标志位用于控制此循环机制,如果replacement是以http://或https://开头,则替换结果会直接以重向返回给客户端, 即永久重定向301

rewrite flag使用介绍:

利用nginx的rewrite的指令,可以实现url的重新跳转,rewrtie有四种不同的flag,分别是redirect(临时重定向)、permanent(永久重定向)、break和last。其中前两种是跳转型的flag,后两种是代理型,跳转型是指有客户端浏览器重新对新地址进行请求,代理型是在WEB服务器内部实现跳转的。Syntax: rewrite regex replacement [flag]; #通过正则表达式处理用户请求并返回替换后的数据包。 Default: —Context: server, location, if

redirect;
#临时重定向,重写完成后以临时重定向方式直接返回重写后生成的新URL给客户端,由客户端重新发起请求;使用相对路径,或者http://或https://开头,状态码:302
permanent;
#重写完成后以永久重定向方式直接返回重写后生成的新URL给客户端,由客户端重新发起请求,状态码:301last;
#重写完成后停止对当前URI在当前location中后续的其它重写操作,而后对新的URL启动新一轮重写检查;提前重启新一轮循环,不建议在location中使用
break;
#重写完成后停止对当前URL在当前location中后续的其它重写操作,而后直接跳转至重写规则配置块之后的其它配置;结束循环,建议在location中使用

rewrite案例-域名永久与临时重定向

要求:因业务需要,将访问源域名 www.menge.net 的请求永久重定向到www.menge.com

临时重定向不会缓存域名解析记录(A记录),但是永久重定向会缓存。

1
2
3
4
5
6
7
location / {
root /data/nginx/html/pc;
index index.html;
rewrite / http://www.menge.com permanent;
#rewrite / http://www.menge.com redirect;
}
#重启Nginx并访问域名www.menge.net进行测试
永久重定向:

域名永久重定向,京东早期的域名 www.360buy.com 由于与360公司类似,于是后期永久重定向到了 www.jd.com ,永久重定向会缓存DNS解析记录。

临时重定向:

域名临时重定向,告诉浏览器域名不是固定重定向到当前目标域名,后期可能随时会更改,因此浏览器不会缓存当前域名的解析记录,而浏览器会缓存永久重定向的DNS解析记录,这也是临时重定向与永久重定向最大的本质区别。

rewrite案例–URI 重定向:

要求:访问about的请求被转发至images,而访问images传递请求再次被转发至images1,以此测试last和break分别有什么区别:

last与brak:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#Nginx配置:
[root@s2 conf.d]# vim pc.conf
location /break {
rewrite ^/break/(.*) /test$1 break; #break不会跳转到其他的location
return 666 "break";
}
location /last {
rewrite ^/last/(.*) /test$1 last; #last会跳转到其他的location继续匹配新的URI
return 888 "last";
}
location /test {
return 999 "test";
}

重启Nginx并访问测试:
curl --head -L -k http://www.menge.net/break
[root@s3 ~]# curl -L -i http://www.menge.net/break/ #brak不会跳转至location /test中
HTTP/1.1 404 Not Found
Server: nginx
Date: Fri, 15 Mar 2019 19:31:17 GMT
Content-Type: text/html
Content-Length: 162
Connection: keep-alive
Keep-Alive: timeout=60
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center>
</body>
</html>
[root@s3 ~]# curl -L -i http://www.menge.net/last/ #last会跳转到location /test继续执行匹配操作
HTTP/1.1 999
Server: nginx
Date: Fri, 15 Mar 2019 19:34:34 GMT
Content-Type: application/octet-stream
Content-Length: 4
Connection: keep-alive
Keep-Alive: timeout=60
test

rewrite案例-自动跳转https:

要求:基于通信安全考虑公司网站要求全站https,因此要求将在不影响用户请求的情况下将http请求全部自动跳转至https,另外也可以实现部分location跳转。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
server {
listen 443 ssl;
listen 80;
ssl_certificate /apps/nginx/certs/www.menge.net.crt;
ssl_certificate_key /apps/nginx/certs/www.menge.net.key;
ssl_session_cache shared:sslcache:20m;
ssl_session_timeout 10m;
server_name www.menge.net;
location / {
root /data/nginx/html/pc;
index index.html;
if ($scheme = http ){ #未加条件判断,会导致死循环
rewrite / https://www.menge.net permanent;
}
}
}

重启Nginx并访问测试
[root@s3 ~]# curl -L -k -i https://www.menge.net/
HTTP/1.1 200 OK
Server: nginx
Date: Fri, 15 Mar 2019 19:53:07 GMT
Content-Type: text/html
Content-Length: 7
Last-Modified: Thu, 14 Mar 2019 14:54:50 GMT
Connection: keep-alive
Keep-Alive: timeout=60
ETag: "5c8a6b3a-7"
Accept-Ranges: bytes
pc web

rewrite案例-判断文件是否存在

要求:当用户访问到公司网站的时输入了一个错误的URL,可以将用户重定向至官网首页。

1
2
3
4
5
6
7
8
9
location / {
root /data/nginx/html/pc;
index index.html;
if (!-f $request_filename) {
#return 404 "linux35";
rewrite (.*) http://www.menge.net/index.html;
}
}
#重启Nginx并访问测试

Nginx防盗链:

Module: ngx_http_referer_module
防盗链基于客户端携带的referer实现,referer是记录打开一个页面之前记录是从哪个页面跳转过来的标记信息,如果别人只链接了自己网站图片或某个单独的资源,而不是打开了网站的整个页面,这就是盗链,referer就是之前的那个网站域名,正常的referer信息有以下几种:
none:请求报文首部没有referer首部,比如用户直接在浏览器输入域名访问web网站,就没有referer信息。
blocked:请求报文有referer首部,但无有效值,比如为空。
server_names:referer首部中包含本主机名及即nginx 监听的server_name。
arbitrary_string:自定义指定字符串,但可使用作通配符。
regular expression:被指定的正则表达式模式匹配到的字符串,要使用开头,例如:.
.menge.com

正常通过搜索引擎搜索web 网站并访问该网站的referer信息如下:
==> /apps/nginx/logs/access_json.log <==
{“@timestamp”:”2019-02-28T13:58:46+08:00”,”host”:”192.168.7.102”,”clientip”:”192.168.0.1”,”size”:0,”responsetime”:0.000,”upstreamtime”:”-“,”upstreamhost”:”-“,”http_host”:”www.menge.net","uri":"/index.html","domain":"www.menge.net","xff":"-","referer":"https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=www.menge.net&oq=www.mageedu.net&rsv_pq=d63060680002eb69&rsv_t=de01TWnmyTdcJqph7SfI1hXgXLJxSSfUPcQ3QkWdJk%2FLNrN95ih3XOhbRs4&rqlang=cn&rsv_enter=1&inputT=321&rsv_sug3=41&rsv_sug2=0&rsv_sug4=1626","tcp_xff":"","http_user_agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, likeGecko) Chrome/72.0.3626.119 Safari/537.36”,”status”:”304”}

实现web盗链:

在一个web 站点盗链另一个站点的资源信息,比如图片、视频等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
[root@s2 conf.d]# pwd
/apps/nginx/conf/conf.d
[root@s2 conf.d]# cat menge.net.conf
server {
listen 80;
server_name www.menge.net;
location / {
index index.html;
root "/data/nginx/html/mageedu";
access_log /apps/nginx/logs/www.menge.net.log access_json;
}
}

#准备盗链web页面:
[root@s2 conf.d]# mkdir /data/nginx/html/menge
[root@s2 conf.d]# cat /data/nginx/html/menge/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>盗链页面</title>
</head>
<body>
<a href="http://www.menge.net">测试盗链</a>
<img src="http://www.menge.net/images/1.jpg">
</body>
</html>

#重启Nginx并访问http://www.menge.net/测试
#验证两个域名的日志,是否会在被盗连的web站点的日志中出现以下盗链日志信息:
==> /apps/nginx/logs/access_json.log <==
{"@timestamp":"2019-02-28T13:27:37+08:00","host":"192.168.7.102","clientip":"192.168.0.1","size":0,"responsetime":0.000,"upstreamtime":"-","upstreamhost":"-","http_host":"www.menge.net","uri":"/images/1.jpg","domain":"www.menge.net","xff":"-","referer":"http://www.mageedu.net/","tcp_xff":"","http_user_agent":"Mozilla/5.0(Windows NT 6.1; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0","status":"304"}

实现防盗链:

文档:https://nginx.org/en/docs/http/ngx_http_referer_module.html#valid_referers
基于访问安全考虑,nginx支持通过ungx_http_referer_module模块 检查访问请求的referer信息是否有效实现防盗链功能,定义方式如下:

1
2
3
4
5
6
7
8
9
10
[root@s2 ~]# vim /apps/nginx/conf/conf.d/pc.conf
location /images {
root /data/nginx/html/pc;
index index.html;
valid_referers none blocked server_names
*.example.com example.* www.example.org/galleries/
~\.google\.;
if ($invalid_referer) {
return 403;
}

定义防盗链:

1
2
3
4
5
6
7
8
9
10
location ^~ /images {
root /data/nginx;
index index.html;
valid_referers none blocked server_names *.menge.com www.menge.*
api.online.test/v1/hostlist ~\.google\. ~\.baidu\.; #定义有效的referer
if ($invalid_referer) { #假如是使用其他的无效的referer访问:
return 403; #返回状态码403
}
}
#重启Nginx并使用浏览器访问盗链网站 www.menge.net, 验证是否提前状态码403:
0%