1. Nginx基本概念
1.1 常见服务器对比
截止2021年web服务器市场市占率,数据来源:https://news.netcraft.com/
服务器名称 | 简介 | 特点 |
---|---|---|
IIS | 全称(Internet Information Services)即互联网信息服务,是由微软公司提供的基于 windows 系统的互联网基本服务。windows 作为服务器在稳定性与其他一些性能上都不如类 UNIX 操作系统,因此在需要高性能 Web 服务器的场合下,IS 可能就会被“冷落“ | |
Tomcat | Tomcat是一个运行Servlet和JSP的Web应用软件,Tomcat技术先进、性能稳定而且开放源代码,因此深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的 Web 应用服务器。但是 Tomcat 天生是一个重量级的 Web服务器,对静态文件和高并发的处理比较弱 | 并发量200~300 |
Apache | Apache 的发展时期很长,同时也有过一段辉煌的业绩。从上图可以看出大概在 2014 年以前都是市场份额第一的服务器。Apache 有很多优点,如稳定、开源、跨平台等。但是它现的时间太久了,在它兴起的年代,互联网的产业规模远远不如今天,所以它被设计成一个重量级的、不支持高并发的 Web 服务器。在 Apache 服务器上,如果有数以万计的并发 HTTP 请求同时访问,就会导致服务器上消耗大量能存,操作系统内核对成百上干的 Apache 进程做进程间切换也会消耗大量的 CPU 资源,并导致 HTTP 请求的平均响应速度降低,这些都决定了 Apache 不可能成为高性能的Web服务器。这也促使了 Lighttpd 和 Nginx 的出现 | |
Lighttpd | Lighttpd 是德国的一个开源的 Web 服务器软件,它和Nginx一样,都是轻量级、高性能的 Web 服务器,欧美的业界开发者比较钟爱Lighttpd,而国内的公司更多的青睐Nginx,同时网上Nginx的资源要更丰富些 | |
其他服务器 | Google Servers(不开源), Weblogic(收费), Webshpere (IBM,收费) |
1.2 Nginx功能特性
(1) 速度更快、并发更高
单次请求或者高并发请求的环境下,Nginx 都会比其他 Web 服务器响应的速度更快。一方面在正常情况下,单次请求会得到更快的响应,另一方面,在高峰期(如有数以万计的并发请求), Nginx 比其他Web 服务器更快的响应请求。Nginx 之所以有这么高的并发处理能力和这么好的性能原因在于 Nginx采用了多进程和I/O多路复用(epoll)的底层实现。单台服务器可达5w并发量。
(2) 配置简单,扩展性强
Nginx的设计极具扩展性,它本身就是由很多模块组成,这些模块的使用可以通过配置文件的配置来添加。这些模块有官方提供的也有第三方提供的模块,如果需要完全可以开发服务自己业务特性的定制模块。
(3) 高可靠性
Nginx 采用的是多进程模式运行,其中有一个 master 主进程和 N 多个 workeri进程,worker 进程的数量我们可以手动设置,每个 worker 进程之间都是相互独立提供服务,并且 master 主进程可以在某一个 workeri进程出错时,快速去拉起新的 worker 进程提供服务。
(4) 热部署
现在互联网项目都要求以 7*24 小时进行服务的提供,针对于这一要求,Nginx 也提供了热部署功能,即可以在 Nginx 不停止的情况下,对 Nginx 进行文件升级、更新配置和更换日志文件等功能。
(5) 成本低、BSD 许可证
BSD 是个开源的许可证,世界上的开源许可证有很多,现在比较流行的有六种分别是GPL、BSD、MIT、Mozilla、Apache、LGPL。在此背景下,Nginx发展出了一些优秀的衍生产品,比如openresty(nginx+lua)、tengine等。
1.3 Nginx常用功能
基本 HTTP 服务
Nginx 可以提供基本 HTTP 服务,可以作为 HTTP 代理服务器和反向代理服务器,支持通过缓存加速访问,可以完成简单的负载均衡和容错,支持包过滤功能,支持 SSL 等。
- 处理静态文件、处理索引文件以及支持自动索引
- 提供反向代理服务器,并可以使用缓存加上反向代理,同时完成负载均衡和容错
- 提供对 FastCGI、memcached 等服务的缓存机制,同时完成负均衡和容错
- 使用 Nginx 的模块化特性提供过器功能。Nginx 基本过滤器包括 gzip 压缩、ranges支持、chunked响应、XSLT、SS 以及图像缩放等。其中针对包含多个 SS 的页面,经由 Fastcgi 或反向代理,SS 过滤器可以并行处理
- 支持 HTTP 下的安全套接层安全协议 SSL
- 支持基于加权和依赖的优先权的 HTTP/2
高级 HTTP 服务
- 支持基于名字和IP的虚拟主机设置
- 支持HTTP/1.0 中的 Keep- Alive 模式和管线(Pipelined)模型连接
- 自定义访问日志格式、带存的日志写操作以及快速日志轮转
- 提供 3xx-5xx 错误代码重定向功能
- 支持重写(Rewrite)模块扩展
- 支持重新加载配置以及在线升级时无需中断正在处理的请求支持网络监控
- 支持 FLV 和 MP4 流媒体传输
邮件服务
Nginx 提供邮件代理服务也是其基本开发需求之ー,主要包含以下特性:
- 支持 IMPA/POP3代理服务功能
- 支持内部 SMTP 代理服务功能
2. 安装准备
2.1 下载地址
nginx官网地址:http://nginx.org/
2.2 系统准备
虚拟机网络适配器设置
推荐使用NAT
关闭防火墙
Linux关闭防火墙:
# 方式一:关闭运行的防火墙,系统重新启动后,防火墙将重新打开
systemctl stop firewall
# 方式二:永久关闭防火墙,,系统重新启动后,防火墙依然关
systemctl disable firewall
# 查看防火墙状态
systemctl status firewa11d
停用selinux
Selinux (security-enhanced linux)是美国安全局对于强制访问控制的实现,在 Linux2.6 内核以后的版本中,selinux 已经成为内核中的一部分。可以说 selinux是 Linux 史上最杰出的新安全子系统之一。虽然有了 selinux,我们的系统会更安全,但是对于我们的学习 Nginx 的历程中,会多很多设置,所以这块建议大家将 selinux 进行关闭。
# 关闭selinux
vim /etc/selinux/config
# 将SELINUX改为=disable,然后重启系统
# 查看selinux运行状态
sestatus
2.3 源码安装
安装GCC编译器
yum install -y gcc
gcc --version
安装PCRE
Nginx 在编译过程中需要使用到 PCRE 库(perl Compatible Regular Expression 兼容正则表
达式库),因为在 Nginx 的 Rewrite 模块和 http 核心模块都会使用到 PCRE 正则表达式语法。
# 可以使用命令进行安装
yum insta1l -y pcre pcre-devel
# 查看是否安装成功
rpm -qa pcre pcre-devel
安装zlib
zlib 库提供了开发人员的压缩算法,在 Nginx 的各个模块中需要使用 gzip 压缩,所以我们也需要提前安装其库及源代码 zlib 和 zlib-devel。
yum insta1l -y z1ib z1ib-devel
rpm -qa z1b z1ib-devel
安装Openssl
Openssl 是一个开放源代码的软件库包,应用程序可以使用这个包进行安全通信,并且避免被窃听。
SSL: Secure Sockets Layer安全套接协议的缩写,可以在 Internet 上提供秘密性传输,其目标是保证两个应用间通信的保密性和可靠性。在 Nginx 中,如果服务器需要提供安全网页时就需要用到 openssl 库,所以我们需要对 OpenSSL 的库文件及它的开发安装包进行一个安装。
yum insta1l -y openssl openssl-deve1
rpm -qa openssl openssl-devel
上述命令,一个个来的话比较麻烦,我们也可以通过一条命令来进行安装
# 进行全部安装
yum install -y gcc pcre pcre-devel zlib zlib-devel openssl openssl-devel
下载nginx源码并解析运行:
# 进入官网查找需要下载版本的链接地址,然后使用 wget 命令进行下载,也可以浏览器下载,看哪个快
wget http://nginxorg/download/nginx-1.16.1.tar.gz
# 建议大家将下的资源进行包管理
mkdir -p nginx/core
mv nginx-1.16.1.tar.gz nginx/core
# 解压缩
tar -zxf nginx-1.16.1.tar.gz
# 进入资源文件中,发现configure,configure是一个脚本,不指定任何参数,直接执行之
./configure
# 编译
make
# 安装,也可以make && make install一起执行
make install
# 安装完成后进入nginx安装目录
cd /usr/local/nginx
# 运行可执行文件
./sbin/nginx
检查运行效果:打开浏览器,输入本机IP地址,能看到nginx欢迎页面就说明运行成功。如果一直loading,则检查下系统防火墙等。
上面我们没有给安装脚本configure指定任何参数,实际上configure提供了很多自定义安装配置参数,比较常用的比如:
# 指向Nginx的安装目录,默认值为/usr/loca/nginx
--prefix=PATH
# 指向(执行)程序文件(nginx)的路径,默认值为<prefix>/sbin/nginx
--sbin-path=PATH
# 指向 Nginx 动态模块安装目录,默认值为<prefix> /modules
--modules-path=PATH
# 指向配置文件nginx.conf的路径,默认值为 <prefix>/conf/nginx.conf
--conf-path=PATH
# 指向错误日志文件的路径, 默认值为 <prefix>/logs/error.log
--error-log-path=PATH
# 指向访日志文件的路径, 默认值为 <prefix>/logs/access.log
--http-log-path=path
# 指向 Nginx 启动后进行ID的文件路径, 默认值为 <prefix>/logs/nginx.pid
--pid-path=PATH
# 指向 Nginx 锁文件的存放路径,默认值为 <prefix>/logs/nginx.lock
--lock-path=PATH
configure脚本配置示例:
./configure --prefix=/usr/local/nginx \
--sbin-path=/usr/local/nginx/sbin/nginx \
--modules-path=/usr/local/nginx/modules
configure配置只能在安装时指定,需要修改时需重装nginx
2.4 使用yum安装
Install the prerequisites:
sudo yum install yum-utils
To set up the yum repository, create the file named /etc/yum.repos.d/nginx.repo
:
vim /etc/yum.repos.d/nginx.repo
with the following contents:
[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:
sudo yum-config-manager --enable nginx-mainline
To install nginx, run the following command:
sudo yum install nginx
When prompted to accept the GPG key, verify that the fingerprint matches 573B FD6B 3D8F BC64 1079 A6AB ABF5 BD82 7BD9 BF62, and if so, accept it.
2.5 更多系统安装方式
2.5 Nginx服务操作
信号控制
前面在提到 Nginx 的高性能,其实也和它的架构模式有关。Nginx 默认采用的是多进程的方式来工作的。nginx 启动后,我们通过 ps- ef I grep nginx
命令可以查看到如下内容:
这里master进程是我们需要打交道的进程,它的pid跟前面提到的/logs/nginx.pid文件中记录的内容是一样的
从上图中可以看到,Nginx 后台进程中包含一个master 进程和多个worker进程,master进程主要用来管理 worker 进程,包含接收外界的信息,并将接收到的信号发送给各个 worker进程,监控worker进程的状态,当worker进程出现异常退出后,会自动重新启动新的worker进程。而worker进程则是专门用来处理用户请求的,各个worker进程之间是平等的并且相互独立,处理请求的机会也是一样的。nginx 的进程模型,我们可以通过下图来说明下:
作为管理员,只需要通过给 master 进程发送信号就可以来控制 Nginx,这个时候我们需要有两个前提条件,一个是要操作的 master 进程,一个是信号。
信号 | 作用 |
---|---|
TERM/INT | 立即关闭整个服务 |
QUIT | 优雅“地关闭整个服务 |
HUP | 重读配置文件并使用服务对新配置项生效 |
USR1 | 重新打开日志文件,可以用来进行日志切割 |
USR2 | 平滑升级到最新版的 nginx |
WINCH | 所有Worker进程不在接收处理新连接,相当于给 Worker 进程发送 QUIT 指令,而master不会受影响 |
调用格式为:kill- signal PID
- signal:即为信号;
- PID: 即为获取到的 master 进程pid;
示例:发送 TERM/INT1 信号给 master 进程,会将 Nginx 服务立即关闭。
kill -TERM PID
kill -TERM `cat /usr/local/nginx/logs/nginx.pid`
kill -INT PID
kill -INT `cat /usr/local/nginx/logs/nginx.pid`
示例: 发送 USR2 信号给 master 进程,告诉 master 进程要平滑升级,这个时候,会重新开启对应的 master 进程和 ork 进程,整个系统中将会有两个 master 进程, 并且新的 master进程的PID会被记录在/usr/local/nginx/logs/nginx.pid
而之前的日的 master进程PID会被记录在/usr/local/nginx/logs/nginx.pid.oldbin
文件中,接着再次发送 QUT 信号给旧的 master 进程,让其处理完请求后再进行关闭
kill -USR2 PID
kill -QUIT PID
命令行控制
命令 | 说明 |
---|---|
-v | 仅打印版本号 |
-V | 打印详细信息 |
-t | 检测nginx.conf文件是否有语法错误 |
-T | 检测nginx.conf文件是否有语法错误,如果检测成功会打印详细信息 |
-q | quiet,只输出错误信息,可以与其他命令结合使用比如:-tq |
-s signal | stop:类似于TERM/INT quit:类似于QUIT reopen:类似于USER1 reload:类似于HUP |
-p prefix | 指定prefix路径 |
-c filename | 指定配置文件路径,可以与其他命令结合使用比如:-tc |
-g directives | 用来补充nginx配置文件,向nginx服务指定启动时的全局配置 |
启停
# 停止nginx
./nginx stop
# 启动nginx
./nginx
# 重启Nginx
./nginx reopen
# 热加载Nginx
./nginx reload
卸载
# 第一步:需要将 nginx 的进程关闭
./nginx -s stop
# 第二步:将安装的 nginx 程序进行删除
rm -rf /usr/local/nginx
# 第三步:cd到安装包解压的存放路径,将configure编译产物清除掉
make clean
在线平滑升级
修改配置文件并生效
vim /user/local/nginx/conf/nginx.conf
# make some modification...
# test if the config is valid
./nginx -t
# for most config changes, just reload to take effect
./nginx -s reload
nginx配置成系统服务(centos)
- 在/usr/lib/systemd/system目录下添加nginx.service:
vim /usr/lib/systemd/system/nginx.service
内容如下:
[Unit]
Description=nginx web service
Documentation=http://nginx.org/en/docs/
After=snetwork, target
[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecstartPre=/usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf
Execstart=/usr/local/nginx/sbin/nginx
ExecReload=/usr/local/nginx/sbin/nginx -s reload
Execstop=/usr/local/nginx/sbin/nginx -s stop
PrivateTmp=true
[Install]
WantedBy=default.target
- 添加完成后如果权限有问题需要进行权限设置
chmod 755 /usr/lib/systemd/system/nginx.service
- 使用这些命令
# 启动:
systemctl start nginx
# 停止:
systemctl stop nginx
# 重启:
systemctl restart nginx
# 重新加载配置文件:
systemctl reload nginx
# 查看nginx状态:
systemctl status nginx
# 开机启动:
systemctl enable nginx
- Mac OS中类似的功能称为alias,即别名;
- Windows也可以通过service install设置为系统服务;
nginx配置到环境变量
修改/etc/profile
文件:
vim /etc/profile
按G跳转到文件尾部,添加以下内容:
export PATH=$PATH:/usr/local/nginx/sbin
:wq
保存退出,再执行下面命令使环境变量生效:
source /etc/profile
测试效果:
nginx -V
2.6 nginx目录结构
3 基础配置介绍
events、http、server、location、upstream等都是块配置项。块配置项可以嵌套。内层块直接继承外层快,例如:server块里的任意配置都是基于http块里的已有配置的。
3.1 全局块
##Nginx worker进程运行的用户及用户组
#语法:user username[groupname] 默认:user nobody nobody
#user用于设置master进程启动后,fork出的worker进程运行在那个用户和用户组下。当按照"user username;"设置时,用户组名与用户名相同。
#若用户在configure命令执行时,使用了参数--user=usergroup 和 --group=groupname,此时nginx.conf将使用参数中指定的用户和用户组。
user nobody;
##Nginx worker进程个数:理论上进程数越多,并发处理能力越强,但最大值受硬件限制。
#每个worker进程都是单线程的进程,他们会调用各个模块以实现多种多样的功能。如果这些模块不会出现阻塞式的调用,那么,有多少CPU内核就应该配置多少个进程,反之,有可能出现阻塞式调用,那么,需要配置稍多一些的worker进程。
worker_processes 1;
##ssl硬件加速。
#用户可以用OpneSSL提供的命令来查看是否有ssl硬件加速设备:openssl engine -t
ssl_engine device;
##守护进程(daemon)。是脱离终端在后台允许的进程。它脱离终端是为了避免进程执行过程中的信息在任何终端上显示。这样一来,进程也不会被任何终端所产生的信息所打断。##
##关闭守护进程的模式,之所以提供这种模式,是为了放便跟踪调试nginx,毕竟用gdb调试进程时最繁琐的就是如何继续跟进fork出的子进程了。##
##如果用off关闭了master_proccess方式,就不会fork出worker子进程来处理请求,而是用master进程自身来处理请求
daemon off; #查看是否以守护进程的方式运行Nginx 默认是on
master_process off; #是否以master/worker方式工作 默认是on
##error日志的设置#
#语法: error_log /path/file level;
#默认: error_log / log/error.log error;
#当path/file 的值为 /dev/null时,这样就不会输出任何日志了,这也是关闭error日志的唯一手段;
#leve的取值范围是debug、info、notice、warn、error、crit、alert、emerg从左至右级别依次增大。
#当level的级别为error时,error、crit、alert、emerg级别的日志就都会输出。大于等于该级别会输出,小于该级别的不会输出。
#如果设定的日志级别是debug,则会输出所有的日志,这一数据量会很大,需要预先确保/path/file所在的磁盘有足够的磁盘空间。级别设定到debug,必须在configure时加入 --with-debug配置项。
error_log logs/error.log;
error_log logs/error.log notice;
error_log logs/error.log info;
##pid文件(master进程ID的pid文件存放路径)的路径
pid logs/nginx.pid;
## 引入其他配置文件
include config/my.conf
3.2 events块
events {
#仅对指定的客户端输出debug级别的日志: 语法:debug_connection[IP|CIDR]
#仅以上IP地址的请求才会输出debug级别的日志,其他请求仍然沿用error_log中配置的日志级别。
debug_connection 10.224.66.14; #或是debug_connection 10.224.57.0/24
# 用来配置单个worker进程最大的连接数,默认1024。number值不能大于操作系统支持打开的最大文件句柄数量。
# 这里的连接数不仅仅包括和前端用户建立的连接数,而是包括所有可能的连接数。
worker_connections 1024;
#可以用来解决常说的"惊群"问题,默认on。大致意思是在某一个时刻,客户端发来一个请求连接, Nginx后台
#是以多进程的工作模式,也就是说有多个worker进程会被同时唤醒,但是最终只会有一个进程可以获取到连接,如果
#每次唤醒的进程数目太多,就会影响Nginx的整体性能。如果将上述值设置为on(开启状态),将会对多个Nginx进程
#接收连接进行序列号,一个个来唤醒接收,就防止了多个进程对连接的争抢。
accept_mutex: on|off;
# 是否允许同时接收多个网络连接,默认off。如果被禁止, nginx一个工作进程只能同时接受一个新的连接;
# 否则,一个工作进程可以同时接受所有的新连接,推荐设置成on
multi_accept on|off;
# 用来设置Nginx服务器选择哪种事件驱动来处理网络消息。
# 注意:此处所选择事件处理模型是Nginx优化部分的一个重要内容, method的可选值有select/poll/epoll/kqueue等,
# 之前在准备centos环境的时候,我们强调过要使用linux内核在2.6以上,就是为了能使用epoll函数来优化Nginx.
# 另外这些值的选择,我们也可以在编译的时候使用
# --with-select_module,--without-selectmodule
# --with-pol1_module.--without-po11_module
# 来设置是否需要将对应的事件驱动模块编译到Nginx的内核。
use: epoll;
}
3.3 http块
核心转储(coredump):在Linux系统中,当进程发生错误或收到信号而终止时,系统会将进程执行时的内存内容(核心映像)写入一个文件(core文件),以作为调试只用,这就是所谓的核心转储(coredump).
http {
# 嵌入其他配置文件 语法:include /path/file,可以是绝对路径也可以是相对路径(相对于Nginx的配置目录,即nginx.conf所在的目录)
# 比如:include /path/*.conf表示引入path下所有conf后缀的文件
include mime.types;
# default_type可以在http/server/location三个块中设置
# application/octet-stream的类型的内容会让浏览器以附件下载方式打开
default_type application/octet-stream;
# 设置访问日志的内容格式和文件路径,其中access_log可在http/server/location块中设置,log_format仅能在http块中设置
# 查看日志的命令: tail -f /path/to/log_file
# 下面log_format配置中main仅仅是个名字,可以随便取,比如:myformat,这个格式名称将在access_log配置中使用
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
log_format myformat '====>my log format';
access_log logs/access.log main;
# 设置Nginx服务器是否使用sendfile)传输文件,默认off。可在http/server/location块中设置。
# 该属性可以大大提高Nginx处理静态资源的性能
sendfile on;
tcp_nopush on;
# 设置长连接的超时时长,默认75s,0表示每次使用完链接立即断开。可在http/server/location块中设置。
keepalive_timeout 65;
# 设置一个keep-alive连接使用的次数,可在http/server/location块中设置。
keepalive_requests 100;
gzip on;
# 一个http可以放多个server块,一个server块可以放多个location块
# 可以把每个server的配置文件写在独立的conf文件中,比如:server{ ... }
# 通常一个域名对应一个server,server_name即域名
server {
# listen监听的端口,语法:listen address:port [ default(deprecated in 0.8.21) | default_server | [ backlog=num | rcvbuf=size | sndbuf=size | accept_filter=filter | deferred | bind | ssl ] ]
# default_server: 在找不到服务时则访问默认服务,如果没有设置这个参数,那么将会以在nginx.conf中找到的第一个server块作为默认server块
listen 8080;
# 主机名称:其后可以跟多个主机名称(localhost/IP/domain),用空格分隔。
# 通配符*可以出现在域名首尾,但不能在中间,比如可以*.test.com或者www.test.*,但不能www.*.com;
# 正则必须以~开头
# 开始处理一个HTTP请求时,nginx会取出header头中的Host,与每个server中的server_name进行匹
# 配,以此决定到底由那一个server来处理这个请求。有可能一个Host与多个server块中的server_name
# 都匹配,这时会根据匹配优先级来选择实际处理的server块。
# server_name匹配优先级:精确匹配>首部通配符>尾部通配符>正则>默认服务。
server_name localhost;
charset koi8-r;
access_log logs/host.access.log main;
# location 语法: location [=|~|~*|^~|@] /uri/ { ... },其中uri不可重复
# location时有顺序的,当一个请求有可能匹配多个location时,实际上这个请求会被第一个location处理。
# 默认:path startWith指定uri即可
# =:path必须精确匹配uri
# ~:正则,区分大小写
# ~*:正则,不区分大小写
# ^~:非正则,匹配成功则不继续匹配,默认会以正则优先
location / {
# 指定资源所在目录,最终path=root/uri
root html;
# 指定location uri的别名,最终path=alias
alias default
# 指定网站默认首页
index index.html index.htm;
# 指定反向代理,即把对该server的访问重定向到指定url去
proxy_pass http://192.168.1.60;
}
# 访问方式:浏览器输入:本机ip:port/get_text,就会显示下面的文本,响应迅速
location /get_text {
# 这里也可以设置成text/plain
default_type text/html;
return 200 "This is nginx's text"
}
location /get_json {
default_type application/json;
return 200 '{"name":"TOM", "age":18}';
}
# 指定错误页面,可以指定多个,页面路径可以是相对路径,也可以是完整的http url
error_page 404 /404.html;
error_page 403 @jump_to_err;
location @jump_to_err {
default_type text/plain;
return 403 "not allowed";
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# 把405状态码改成200返回个用户
error_page 405 =200 /405.html;
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.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;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
# 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;
# }
#}
为什么要使用keep-alive?
我们都知道HTTP是一种无状态协议,客户端向服务端发送一个TCP请求,服务端响应完毕后断开连接。
若客户端向服务端发送多个请求,每个请求都需要重新创建一次连接,效率相对来说比较低,使用keepalive模式,可以告诉服务器端在处理完一个请求后保持这个TCP连接的打开状态,若接收到来自这个客户端的其他请求,服务端就会利用这个未被关闭的连接,而不需要重新创建一个新连接,提升效率,但是这个连接也不能一直保持,这样的话,连接如果过多,也会是服务端的性能下降,这个时候就需要我们进行设置其的超时时间。
3.4 全局变量
在log_format
中,使用到了全局变量,全局变量使用$
引用,一些常用的变量如下:
变量名 | 说明 |
---|---|
$host | 请求信息中的 Host,如果请求中没有 Host 行,则等于设置的服务器名,不包含端口 |
$request_method | 客户端请求类型,如 GET、POST r e m o t e a d d r 客 户 端 的 I P 地 址 remote_addr客户端的 IP 地址 remoteaddr客户端的IP地址args请求中的参数 |
$arg_PARAMETERGET | 请求中变量名 PARAMETER 参数的值,例如:$http_user_agent(Uaer-Agent 值), $http_referer… |
$content_length | 请求头中的 Content-length 字段 |
$http_user_agent | 客户端agent信息 |
$http_cookie | 客户端cookie信息 |
$remote_addr | 客户端的IP地址 |
$remote_port | 客户端的端口 |
$http_user_agent | 客户端agent信息 |
$server_protocol | 请求使用的协议,如 HTTP/1.0、HTTP/1.1 |
$server_addr | 服务器地址 |
$server_name | 服务器名称 |
$server_port | 服务器的端口号 |
$scheme | HTTP 方法(如http,https) |
更多变量可以直接搜索关键字「nginx内置预定义变量」。
4 静态资源部署
静态资源即指在服务器端真实存在并且能直接拿来展示的一些文件,比如常见的html页面、css文件、js文件、图片、视频等资源;
动态资源即指在服务器端真实存在但是要想获取需要经过一定的业务逻辑处理,根据不同的条件展示不同内容,比如jsp、servlet、ftl以及常见的报表数据、用户数据等资源;
动静分离即指静态资源的请求直接交给资源目录获取,动态资源请求则利用反向代理转发给对应后台处理。
静态资源配置语法
主要涉及到三个配置:
sendfile on;
tcp_nopush on;
tcp_nodelay on;
sendfile
用来开启高效的文件传输模式(零拷贝-用户区无copy)。请求静态资源的过程:客户端通过网络接口向服务端发送请求,操作系统将这些客户端的请求传递给服务器端应用程序,服务器端应用程序会处理这些请求,请求处理完成以后,操作系统还需要将处理得到的结果通过网络适配器传递回去。
tcp_nopush
该指令必须在sendfile打开的状态下才会生效,默认关闭。主要是用来提升网络包的传输效率
tcp_nodelay
该指令必须在keep-alive连接开启的情况下才生效,默认打开。来提高网络包传输的实时性。
发送数据的两种策略:
- 无buff,有数据就发,实时性高,但效率不高,对应nodelay;
- 有buff,buff满了才发,效率高,但实时性不高,对应nopush;
“tcp nopush"和"tcp nodelay"看起来是"互斥的”,那么为什么要将这两个值都打开,这个大家需要知道的是在linux2.5.9以后的版本中两者是可以兼容的,三个指令都开启的好处是, sendfile可以开启高效的文件传输模式, tcpnopush开启可以确保在发送到客户端之前数据包已经充分"填满",这大大减少了网络开销,并加快了文件发送的速度。然后,当它到达最后一个可能因为没有"填满"而暂停的数据包时, Nginx会忽略tcp-nopush参数,然后, tcp-nodelay强制套接字发送数据。由此可 知, TCPNOPUSH可以与TCP-NODELAY一起设置,它比单独配置TCPNODELAY具有更强的性能。
静态资源压缩
客户端:Accept-Encoding: gzip
表明自己支持gzip压缩,浏览器默认支持该项,且通常不止支持一种压缩方式
服务器:检测到客户端支持后,会返回压缩后的文件并添加Content-Encoding: gzip
告诉客户端自己采用的压缩方式
nginx处理和解析gzip相关指令的模块有:
- ngx_http_gzip_module模块:默认安装
- ngx_http_gzip_static_module模块:需配置,解决gzip与sendfile共存问题
- ngx_http_gunzip_module模块:需配置,解压缩gz文件
相关配置及说明:
# /etc/nginx/conf.d/gzip.conf
# 默认off,是否开启gzip
gzip on;
# 要采用gzip压缩的MIME文件类型,默认只有text/html,可以使用*表示压缩所有类型,但实际不推荐,因为图片等资源很多已经被压缩过了,防止二次压缩徒增服务器压力
# 支持压缩的文件类型可以从default_type中引入的mime.types文件获取
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
# ==========上面两个开启基本就能跑起了,下面的愿意折腾就了解一下==========
# 默认off,需先安装ngx_http_gzip_static_module模块,启用后,Nginx首先检查是否存在请求静态文件的gz结尾的文件,如果有则直接返回该.gz文件,开启后需要关闭gzip
gzip_static on;
# 默认off,nginx做为反向代理时启用,用于设置代理服务器是否对服务器返回的内容进行gzip压缩
gzip_proxied any;
# 用于在响应消息头中添加 Vary:Accept-Encoding,使代理服务器根据请求头中的Accept-Encoding识别是否启用 gzip 压缩
gzip_vary on;
# gzip压缩比,压缩级别是 1-9,1 压缩级别最低,9 最高,级别越高压缩率越大,压缩时间越长,建议 4-6
gzip_comp_level 6;
# 获取多少内存用于缓存压缩结果,16 8k 表示以 8k*16 为单位获得,不建议修改
gzip_buffers 16 8k;
# 允许压缩的页面最小字节数,页面字节数从header头中的 Content-Length 中进行获取。
# 默认值是 0,不管页面多大都压缩。建议设置成大于 1k 的字节数,小于 1k 可能会越压越大
gzip_min_length 1k;
# 默认 1.1,启用 gzip 所需的HTTP最低版本,不建议修改
gzip_http_version 1.1;
# 针对不同种类客户端发起的请求,可以选择性地开启和关闭gzip,参数是一个正则,用来过滤掉明显不支持gzip的user-agent
gzip_disable "MSIE [1-6]\.";
gzip_proxied可选值 | 说明 |
---|---|
off | 关闭Nginx服务器对后台服务器返回结果的Gzip压缩 |
expired | 启用压缩,如果header头中包含"Expires"头信息 |
no-cache | 启用压缩,如果header头中包含"Cache-Control:no-cache"头信息 no-store-启用压缩,如果header头中包含"Cache-Controlno-store"头信息 |
private | 启用压缩,如果header头中包含"Cache-Control:private"头信息 no_last-modified-启用压缩,如果header头中不包含"Last-Modified"头信息 |
no etag | 启用压缩,如果header头中不包含"ETag"头信息 |
auth | 启用压缩,如果header头中包含"Authorization"头信息 |
any | 无条件启用压缩 |
gzip压缩的流程:
- 客户端请求是否支持gzip,若不支持,则不压缩;
- 请求资源大小是否达到gzip压缩阈值,若未达到,则不压缩;
- 请求资源是否已存在*.gz文件,若已存在,则不压缩,直接返回gz文件;
- 服务器对资源进行压缩,生成*.gz,并返回gz文件;
从上面流程可以看出,如果资源文件已经有现成的压缩产物,则服务器会直接返回,从而可以节省服务的开销。因此一般推荐Webpack打包时开启gzip压缩或者使用gzip命令对文件进行压缩。
gzip与sendfile共存问题
前面提到sendfile开启后nginx将会采用零拷贝方式利用系统文件系统直接发送文件到socket缓冲区,而不经过用户区(应用程序),这就使得gzip无法处理静态资源文件了。此时,可以使用上面提到的ngx_http_gzip_static_module
模块解决此问题。
添加ngx_http_gzip_static_module
模块:
# 查询当前Nginx的配置参数
nginx -V
# 将nginx安装目录下sbin目录中的nginx二进制文件进行更名
cd /usr/local/nginx/sbir
mv nginx nginxold
# 进入Nginx的安装包目录
cd /root/nginx/core/nginx-1.16.1
# 执行make clean清空之前编译的内容
make clean
# 使用configure来配置参数
./confiqure --with-http_gzip_static_module
# 使用make命令进行编译
make
# 将objs目录下的nginx二进制执行文件移动到nginx安装目录下的sbin目录中
mv objs/nginx /usr/local/nginx/sbin
# 执行更新命令
make upgrade
静态资源客户端缓存配置
web缓存是指一个web资源(如html页面,图片, js,数据等)存在于web服务器和客户端(浏览器)之间的副本。缓存会根据进来的请求保存输出内容的副本;当下一个请求来到的时候,如果是相同的URL,缓存会根据缓存机制决定是直接使用副本响应访问请求,还是向源服务器再次发送请求,比较常见的就是浏览器会缓存访问过网站的网页,当再次访问这个URL地址的时候,如果网页没有更新,就不会再次下载网页,而是直接使用本地缓存的网页。只有当网站明确标识资源已经更新,浏览器才会再次下载网页。
缓存分类
web缓存根据存放位置,可分为客户端缓存(浏览器缓存等)和服务端缓存(nginx、Redis、Memcached等)。
HTTP协议中缓存相关
服务端header | 说明 | 客户端header | 说明 |
---|---|---|---|
Expires | 缓存过期的日期和时间,给客户端用 | 无 | 当有缓存时判断缓存是否过期 |
Cache-Control | 设置和缓存相关的配置信息 | 无 | 配合Expires的值,判断缓存是否过期 |
Last-Modified | 请求资源最后修改时间 | If-Modified-SInce | 客户端回传Last-Modified给服务器,服务器判断资源是否有更新,无更新返回304,减少网络数据传输 |
ETag | 请求变量的实体标签的当前值,比如文件的MD5值 | If-None-Match | 客户端回传ETag,服务端判断资源有更新 |
nginx相关配置
expires
指令
expires可选值 | 说明 |
---|---|
off | 关闭缓存 |
time | 具体时长,可以整数也可以是负数,指定过期时间,如果是负数, Cache-Control则为no- cache,如果为整数或0,则Cache-Control的值为max-age=time; |
epoch | 指定Expires的值为1 January,1970,00:00:01 GMT(1970-01-01 00:00:00), Cache-Control的值no-cache |
max | 指定Expires的值为31 December2037 23:59:59GMT’ (2037-12-31 23:59:59) Cache-Control的值为10年 |
配置示例:
# 对指定资源类型设置缓存时间,缓存时间默认单位是s,负数表示不缓存
location ~ .*\.(html|js|css|png)$ {
expires 1009;
add_header Cache-Control no-store;
}
add_header
指令
Cache-Control值 | 说明 |
---|---|
must-revalidate | 可缓存但必须再向源服务器进行确认 |
no-cache | 缓存前必须确认其有效性,即弱缓存 |
no-store | 不缓存请求或响应的任何内容 |
no-transform | 代理不可更改媒体类型 |
public | 可向任意方提供响应的缓存 |
private | 仅向特定用户返回响应 |
proxy-revalidate | 要求中间缓存服务器对缓存的响应有效性再进行确认 |
max-age=<秒> | 响应最大Age值 |
s-maxage=<秒> | 公共缓存服务器响应的最大Age值 |
配置示例:
# 对指定资源类型设置缓存时间,缓存时间默认单位是s,负数表示不缓存
location ~ .*\.(html|js|css|png)$ {
expires 1009;
add_header Cache-Control no-store;
}
静态资源跨域
同源:协议、域名(IP)、端口相同即为同源。
同源 | 不同源 |
---|---|
http://www.nginx.org:80/user/1 http://www.nginx.org/user/1 | http://192.168.200.131/user/1 https://192.168.200.131/user/1 http://192.168,200.131/user/1 http://192.168.200.132/user/1 http://192.168.200.131/user/1 http://192.168.200.131:8080/user/1 http://www.nginx. com/user/1 http://www.nginx.org/user/1 http://192.168.200.131/user/1 http://192.168.200.131:8080/user/1 |
add_header
添加相关请求头
请求头 | 说明 |
---|---|
Access-Control-Allow-Origin | 直译过来是允许跨域访问的源地址信息,可以配置多个(多个用逗号分隔),也可以使用*代表所有源 |
Access-Control-Allow-Methods | 直译过来是允许跨域访问的请求方式,值可以为GET/POST/PUT/DELET等,可以全部设置,也可以根据需要设置,多个用逗号分隔 |
server {
add_header Access-Control-Allow-origin http://192.168.200,133 http://192.168.200,131;
add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE;
}
静态资源防盗链
盗链:在自己的页面上引用其他公司服务器的资源。
防盗链原理:通过在资源请求头指定Referer
表明访问源,在服务端判定是否返回数据。
valid-referers
指令
valid-referers
:nginx会通过查看referer自动和valid_referers
后面的内容进行匹配, 如果匹配到了就将$invalid-referer
变量置0,如果没有匹配到,则将$invalid-referer
变量置为1,匹配的过程中不区分大小写。
语法:valid referers nonelblocked |server_names |string…
位置:server, location
- none:如果Header中的Referer为空,允许访问
- blocked:在Header中的Referer不为空,但是该值被防火墙或代理进行伪装过,如不带"http://"、"https://等协议头的资源允许访问。
- server-names:指定具体的域名或者IP
- -string:可以支持正则表达式和*的字符串。如果是正则表达式,需要以~开头表示
例如:
location ~ .*\.(png|jpg|gif)$ {
valid_referers none blocked www.baidu.com;
if ($invalid_referer){
return 403;
}
root html/images;
}
ngx_http_accesskey_module
模块
此为三方模块,具体用法这里不做介绍。
5 rewrite功能
Rewrite是Nginx服务器提供的一个重要基本功能,是Web服务器产品中几乎必备的功能。主要的作用是用来实现URL的重写。
注意:Nginx服务器的Rewrite功能的实现依赖于PCRE的支持,因此在编译安装Nginx服 务器之前,需要安装PCRE库。Nginx使用的是ngx_http_rewrite_module
模块来解析和处理Rewrite功能的相关配置。
Rewrite的相关命令:
- set指令
- if指令
- break指令
- return指令
- rewrite指令
- rewrite_log指令
rewrite规则:
rewrite常用全局变量:
指令 | 说明 | 示例 |
---|---|---|
地址重写 | ||
地址转发 | ||
rewrite | ||
if | ||
break | ||
rewrite_log | ||
set |
域名跳转
二级域名 fe.sherlocked93.club 的请求全都代理到统一的二级域名 be.sherlocked93.club,解决跨域问题:
server {
listen 9001;
server_name fe.sherlocked93.club;
location / {
proxy_pass be.sherlocked93.club;
}
}
为be.sherlocked93.club服务添加header支持跨域:
# /etc/nginx/conf.d/be.sherlocked93.club.conf
server {
listen 80;
server_name be.sherlocked93.club;
# 全局变量获得当前请求origin,带cookie的请求不支持*
add_header 'Access-Control-Allow-Origin' $http_origin;
# 为 true 可带上 cookie
add_header 'Access-Control-Allow-Credentials' 'true';
# 允许请求方法
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
# 允许请求的 header,可以为 *
add_header 'Access-Control-Allow-Headers' $http_access_control_request_headers;
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
if ($request_method = 'OPTIONS') {
# OPTIONS 请求的有效期,在有效期内不用发出另一条预检请求
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204; # 200 也可以
}
location / {
root /usr/share/nginx/html/be;
index index.html;
}
}
静态资源和服务请求用/apis/
加以区分:
# 请求跨域,约定代理后端服务请求path以/apis/开头
location ^~/apis/ {
# 这里重写了请求,将正则匹配中的第一个分组的path拼接到真正的请求后面,并用break停止后续匹配
rewrite ^/apis/(.*)$ /$1 break;
proxy_pass be.sherlocked93.club;
# 两个域名之间cookie的传递与回写
proxy_cookie_domain be.sherlocked93.club fe.sherlocked93.club;
}
域名镜像
独立域名
目录自动添加“/”
目录合并
防盗链
6 反向代理
配置语法
upstream+proxy_pass
配置 | 说明 |
---|---|
proxy_set_header | 在将客户端请求发送给后端服务器之前,更改来自客户端的请求头信息。 |
proxy_connect_timeout | 配置Nginx与后端代理服务器尝试建立连接的超时时间。 |
proxy_read_timeout | 配置Nginx向后端服务器组发出read请求后,等待相应的超时时间。 |
proxy_send_timeout | 配置Nginx向后端服务器组发出write请求后,等待相应的超时时间。 |
proxy_redirect | 用于修改后端服务器返回的响应头中的Location和Refresh。 |
安全隔离
基于IP地址阻止流量及并发数
7 负载均衡
未完待续