Loading

了解Nginx(一)

1. 先了解HTTP

​HTTP全称为Hyper Text Transfer Protocol超文本传输协议,它是基于TCP传输协议构建的应用层协议,作为支撑万维网www的核心协议,为了保证其效率及处理大量事务的能力,因此在设计时,HTTP被制定成为一种无状态协议,也就是说:HTTP本身不会对发送过的请求和相应的通信状态进行持久化处理。

也正因HTTP的无状态特征,所以在有些需要保持状态的场景中,则需要引入其他技术来实现,比如需要保持“登录状态、授权状态”时,需要配合Cookie来实现记录与管理状态。


1.1 HTTP协议工作流程

​HTTP核心由请求与响应构成,是一种典型基于客户端和服务器模型的协议,在目前的网络中,浏览器作为HTTP协议的主要载体,一般来说,“从浏览器发出请求到服务器返回响应”,这个过程被称为一次HTTP操作,也被称为一个事务,其具体过程如下:

image-20230228195246705

  1. 客户端连接WEB服务器:浏览器与服务器的HTTP/80端口建立一个套接字连接。
  2. 发送HTTP请求:根据用户的URL,通过套接字连接向服务器发送对应的请求报文。
  3. 服务器处理请求并返回响应结果:解析请求、定位资源、执行逻辑后将结果写到套接字,客户端从套接字中获取结果。
  4. 释放TCP套接字连接:默认情况下,服务器主动终止套接字连接,客户端被动关闭。

​从建立连接发出请求,到服务器处理完成后,返回响应再关闭连接,既代表着一个“事务”就完成了,但客户端接受到响应后,还会存在:解析响应报文、渲染结果数据这两步操作。

Tips:目前HTTP主流应用版本还是HTTP/1.1、2.0


1.2 HTTP报文的组成结构

​浏览器访问服务器的过程中,解析域名得到具体IP后,会将用户的请求组装成HTTP报文,HTTP报文主要分为请求报文与应答(响应)报文两类。


1.2.1 请求报文

​请求报文主要由请求行、请求头、空行、请求主体四部分组成。

image-20230228200600107

请求行也被称为起始行,主要包含请求方法、资源路径(URI)以及协议版本三部分!


1.2.2 响应报文

​应答报文主要由状态行、响应头、空行、响应主体四部分组成。

image-20230228201110808

应答报文中的状态行主要由协议版本、状态码、状态描述三部分构成!


1.3 请求方法

同时,HTTP协议中发送请求的方法存在多种,HTTP/1.0中提供了三个请求方法,HTTP/1.1中新增六个请求方法:

  • GET:一般用于获取资源数据,如获取用户信息、商品信息、首页数据等。
  • POST:一般用于传输/提交资源数据,如提交表单数据、提交字节数据等。
  • HEAD:向服务器发送类似于GET方式的请求,但只要求返回头信息,不返回主体数据。
  • PUT:一般用于修改数据,向指定路径上的资源提交最新数据并将其全量替换。
  • PATCH:和PUT方法类似,PUT是全量更新,PATCH可以只修改部分数据。
  • DELETE:一般用于删除资源/数据,如移除服务器上某文件资源等。
  • OPTIONS:列出请求的目标资源所支持的请求方法,用来跨域请求。
  • TRACE:追踪客户端请求/服务端响应路径,用于测试或诊断出错。
  • CONNECT:在与代理服务器通信时建立连接隧道,使用隧道进行TCP通信。

其中最常用的是GET/POST两种方式,其他的方法相对比而言,正常业务用的频率并不高。


1.4 HTTP状态码

​常见的200、403、404、500等,这些数字在HTTP协议中专业称呼为:HTTP状态码RFC中规定了状态码必须要为三位数,其中第一个数代表了响应状态的类别,HTTP中所有的状态码共被分为五大类别:

1xx/(Informational):信息性状态码,代表请求被成功接受,正在处理请求。

2xx/(Success):成功状态码,客户端的请求被成功处理并返回。

3xx/(Redirection):重定向状态码,请求的资源位置发生变动,需重新请求。

4xx/(ClientError):客户端错误状态码,客户端请求出现错误导致请求失败。

5xx/(ServerError):服务端错误状态码,请求的服务端内部错误导致请求无法处理。


200:以2开头,代表请求成功,服务端正常接受并处理了该请求。

301:以3开头,代表请求的资源位置发生变动,请求会被重定向,重新请求新位置。

404:以4开头,代表客户端出现错误,请求的路径不正确导致服务端无法定位资源。

500:以5开头,代表服务端出现错误,服务端在处理请求的目标资源时,执行过程出现错误。


如下是常见状态码可能出现的情况

http常见状态码 含义
200 OK 表示正常
301 Moved Permanently 永久跳转
302 Found或Moved Temporarily 临时跳转
304 Not Modified 浏览器访问网站的时候,用户访问的是缓存。
403 Forbidden 拒绝访问/权限拒绝,一般是网站权限设置,网站首页文件问题。
404 Not Found 没有这个文件/目录,你访问的资源服务器的站点目录上没有。用户访问写错了。
500 Internal Server Error 服务器内部错误. 原因一般是服务端配置文件,selinux开启,服务模块没有安装.一般配合服务的错误日志一起查看。
502 Bad Gateway 网关错误,一般在负载均衡,代理服务器中出现,后端的节点都挂了(无法访问)
503 Service Unavailable 服务临时不可用.
故障:后端节点因为负载高,导致临时不可用,显示这个提示。
系统升级: 网站升级的时候可以显示这个状态码。
504 Gateway Timeout(网关超时) 与上面类似: 临时不可用,网络,负载等出现的问题

1.5 网站核心指标

衡量网站访问情况的一些指标,参考如下:

网站的访问情况指标 含义 应用 如何计算
IP 访问你网站的ip数量(公网ip) 分析用户访问情况,只看这个指标容易估算访问量的小了 统计访问日志对ip去重
PV Page View页面访问量(每个页面被访问的次数) 分析用户访问情况的时候,只看这个指标容易导致估算过大 统计日志行数
UV Unique Vistor独立访客数量(用户) 分析用户访问情况的时候,相对准确些 利用第三方插件
DAU Daily Active User日活跃用户(app) 用于分析app活跃度 通过代码与数据库分析
MAU 月活:月度活跃用户 用于分析app活跃度 通过代码与数据库分析

2. 了解并安装Nginx

2.1 简单了解Nginx

​Nginx是目前负载均衡技术中的主流方案,几乎绝大部分项目都会使用它,Nginx是一个轻量级的高性能HTTP反向代理服务器,同时它也是一个通用类型的代理服务器,支持绝大部分协议,如TCP、UDP、SMTP、HTTPS等。


2.2 为什么选择Nginx

​Nginx 是一个高性能的 Web 和反向代理服务器,作为 Web 服务器:相比 Apache,Nginx 使用更少的资源(3万并发连接下,开启10个Nginx线程消耗不到200MB内存),支持更多的并发连接,体现更高的效率,能够支持高达 50,000 个并发连接数的响应。同时可以做缓存加速、负载均衡、节点服务器健康检查等等。


2.3 快速安装Nginx

配置nginx源如下:

[root@web02 ~]# cat /etc/yum.repos.d/nginx.repo
[nginx]
name = nginx stable repo
baseurl = http://nginx.org/packages/centos/$releasever/$basearch/
enabled = 1
gpgcheck = 0

安装、启动、检查

#安装
[root@web02 ~]# yum install nginx -y

#启动
[root@web02 ~]# systemctl start nginx

#设置开机自启动
[root@web02 ~]# systemctl enable nginx
Created symlink from /etc/systemd/system/multi-user.target.wants/nginx.service to /usr/lib/systemd/system/nginx.service.

#查看状态
[root@web02 ~]# systemctl status nginx
● nginx.service - nginx - high performance web server
   Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled)
   Active: active (running) since Tue 2023-02-28 08:17:07 EST; 15s ago
     Docs: http://nginx.org/en/docs/
 Main PID: 57382 (nginx)
   CGroup: /system.slice/nginx.service
           ├─57382 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
           └─57383 nginx: worker process

Feb 28 08:17:06 web02 systemd[1]: Starting nginx - high performance web server...
Feb 28 08:17:07 web02 systemd[1]: Started nginx - high performance web server.

浏览器访问测试

image-20230228212032614


3. 学习Nginx

3.1 Nginx的主要目录和文件

[root@web02 ~]# tree /etc/nginx/  #Nginx各种配置的目录
/etc/nginx/
├── conf.d  #Nginx子配置文件目录
│   └── default.conf
├── fastcgi_params  #nginx与其他服务连接使用的变量文件(配置文件) nginx+php
├── mime.types   #媒体类型,http协议中的文件类型
├── modules -> ../../usr/lib64/nginx/modules  #模块目录
├── nginx.conf  #Nginx主配置文件
├── scgi_params  #少用
└── uwsgi_params ##nginx+python

#对nginx的日志进行切割、防止日志过大的配置文件
/etc/logrotate.d/nginx

#存放nginx的日志:访问日志(access.log)和错误日志(error.log)
/var/log/nginx/

3.2 主配置文件nginx.conf

​Nginx的主配置文件是nginx.conf,这个配置文件一共由三部分组成,分别为全局块、events块和http块。在http块中,又包含http全局块、多个server块。每个server块中,可以包含server全局块和多个location块。在同一配置块中嵌套的配置块,各个之间不存在次序关系。

​配置文件支持大量可配置的指令,绝大多数指令不是特定属于某一个块的。同一个指令放在不同层级的块中,其作用域也不同,一般情况下,高一级块中的指令可以作用于自身所在的块和此块包含的所有低层级块。如果某个指令在两个不同层级的块中同时出现,则采用“就近原则”,即以较低层级块中的配置为准。比如,某指令同时出现在http全局块中和server块中,并且配置不同,则应该以server块中的配置为准。


整个配置文件结构大致如下:

[root@web02 ~]# cat /etc/nginx/nginx.conf
#全局块
user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;

#event块
events {
    worker_connections  1024;
}

#http块
http {
    #http全局块
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    
    #server块    
    server {
            #server全局块
            listen       8000;
            server_name  localhost;
            #location块
            location / {
                root html;
                index index.html index.htm;
            }
            error_page   500 502 503 504  /50x.html;
            location = /50x.html {
                root html;
            }
        }
    
#这边可以有多个server块
    server {
          ...
      }

    include /etc/nginx/conf.d/*.conf;  #可以通过include来引入配置
}

3.2.1 全局块

​全局块是默认配置文件从开始到events块之间的一部分内容,主要设置一些影响Nginx服务器整体运行的配置指令,因此,这些指令的作用域是Nginx服务器全局。

​通常包括配置运行Nginx服务器的用户(组)、允许生成的worker process数、Nginx进程PID存放路径、日志的存放路径和类型以及配置文件引入等。

# 指定可以运行nginx服务的用户和用户组,只能在全局块配置
user [user] [group]
# 将user指令注释掉,或者配置成nobody的话所有用户都可以运行
user nobody nobody;

# 指定工作线程数,可以制定具体的进程数,也可使用自动模式,这个指令只能在全局块配置
worker_processes number | auto;
# 列子:指定4个工作线程,这种情况下会生成一个master进程和4个worker进程
worker_processes 4;

# 指定pid文件存放的路径,这个指令只能在全局块配置
pid logs/nginx.pid;

# 指定错误日志的路径和日志级别,此指令可以在全局块、http块、server块以及location块中配置。(在不同的块配置有啥区别??)
#其中debug级别的日志需要编译时使用--with-debug开启debug开关
error_log [path] [debug | info | notice | warn | error | crit | alert | emerg] 
error_log  logs/error.log  notice;
error_log  logs/error.log  info;

3.2.2 events块

​events块涉及的指令主要影响Nginx服务器与用户的网络连接。常用到的设置包括是否开启对多worker process下的网络连接进行序列化,是否允许同时接收多个网络连接,选取哪种事件驱动模型处理连接请求,每个worker process可以同时支持的最大连接数等。

Tips:这一部分的指令对Nginx服务器的性能影响较大,在实际配置中应该根据实际情况灵活调整。

# 当某一时刻只有一个网络连接到来时,多个睡眠进程会被同时叫醒,但只有一个进程可获得连接。如果每次唤醒的进程数目太多,会影响一部分系统性能。在Nginx服务器的多进程下,就有可能出现这样的问题。
# 开启的时候,将会对多个Nginx进程接收连接进行序列化,防止多个进程对连接的争抢
# 默认是开启状态,只能在events块中进行配置
accept_mutex on | off;

# 如果multi_accept被禁止了,nginx一个工作进程只能同时接受一个新的连接。否则,一个工作进程可以同时接受所有的新连接。 
# 如果nginx使用kqueue连接方法,那么这条指令会被忽略,因为这个方法会报告在等待被接受的新连接的数量。
# 默认是off状态,只能在event块配置
multi_accept on | off;

# 指定使用哪种网络IO模型,method可选择的内容有:select、poll、kqueue、epoll、rtsig、/dev/poll以及eventport,一般操作系统不是支持上面所有模型的。
# 只能在events块中进行配置
use method
use epoll

# 设置允许每一个worker process同时开启的最大连接数,当每个工作进程接受的连接数超过这个值时将不再接收连接
# 当所有的工作进程都接收满时,连接进入logback,logback满后连接被拒绝
# 只能在events块中进行配置
# 注意:这个值不能超过超过系统支持打开的最大文件数,也不能超过单个进程支持打开的最大文件数,具体可以参考这篇文章:https://cloud.tencent.com/developer/article/1114773
worker_connections  1024;

3.2.3 http块

​http块是Nginx服务器配置中的重要部分,代理、缓存和日志定义等绝大多数的功能和第三方模块的配置都可以放在这个模块中。

​前面已经提到,http块中可以包含自己的全局块,也可以包含server块,server块中又可以进一步包含location块,在本文中我们使用“http全局块”来表示http中自己的全局块,即http块中不包含在server块中的部分。

​可以在http全局块中配置的指令包括文件引入、MIME-Type定义、日志自定义、是否使用sendfile传输文件、连接超时时间、单连接请求数上限等。

# 常用的浏览器中,可以显示的内容有HTML、XML、GIF及Flash等种类繁多的文本、媒体等资源,浏览器为区分这些资源,需要使用MIME Type。换言之,MIME Type是网络资源的媒体类型。Nginx服务器作为Web服务器,必须能够识别前端请求的资源类型。

# include指令,用于包含其他的配置文件,可以放在配置文件的任何地方,但是要注意你包含进来的配置文件一定符合配置规范,比如说你include进来的配置是worker_processes指令的配置,而你将这个指令包含到了http块中,着肯定是不行的,上面已经介绍过worker_processes指令只能在全局块中。

# 下面的指令将mime.types包含进来,mime.types和ngin.cfg同级目录,不同级的话需要指定具体路径
include  mime.types;

# 配置默认类型,如果不加此指令,默认值为text/plain。
# 此指令还可以在http块、server块或者location块中进行配置。
default_type  application/octet-stream;

# access_log配置,此指令可以在http块、server块或者location块中进行设置
# log_format指令,用于定义日志格式,此指令只能在http块中进行配置
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  logs/access.log  main;

# 开启关闭sendfile方式传输文件,可以在http块、server块或者location块中进行配置
sendfile  on | off;

# 设置sendfile最大数据量,此指令可以在http块、server块或location块中配置
sendfile_max_chunk size;

# 其中,size值如果大于0,Nginx进程的每个worker process每次调用sendfile()传输的数据量最大不能超过这个值(这里是128k,所以每次不能超过128k);如果设置为0,则无限制。默认值为0。
sendfile_max_chunk 128k;

# 配置连接超时时间,此指令可以在http块、server块或location块中配置。
# 下面配置的含义是,在服务器端保持连接的时间设置为120 s,发给用户端的应答报文头部中Keep-Alive域的超时时间设置为100 s。
# keepalive_timeout 120s 100s

# 配置单连接请求数上限,此指令可以在http块、server块或location块中配置。
# Nginx服务器端和用户端建立会话连接后,用户端通过此连接发送请求。指令keepalive_requests用于限制用户通过某一连接向Nginx服务器发送请求的次数。默认是100
keepalive_requests number;

3.2.4 server块

​server块和“虚拟主机”的概念有密切联系。虚拟主机,又称虚拟服务器、主机空间或是网页空间,它是一种技术。该技术是为了节省互联网服务器硬件成本而出现的。这里的“主机”或“空间”是由实体的服务器延伸而来,硬件系统可以基于服务器群,或者单个服务器等。虚拟主机技术主要应用于HTTP、FTP及EMAIL等多项服务,将一台服务器的某项或者全部服务内容逻辑划分为多个服务单位,对外表现为多个服务器,从而充分利用服务器硬件资源。从用户角度来看,一台虚拟主机和一台独立的硬件主机是完全一样的。

​在使用Nginx服务器提供Web服务时,利用虚拟主机的技术就可以避免为每一个要运行的网站提供单独的Nginx服务器,也无需为每个网站对应运行一组Nginx进程。虚拟主机技术使得Nginx服务器可以在同一台服务器上只运行一组Nginx进程,就可以运行多个网站。

​在前面提到过,每一个http块都可以包含多个server块,而每个server块就相当于一台虚拟主机,它内部可有多台主机联合提供服务,一起对外提供在逻辑上关系密切的一组服务(或网站)。

​和http块相同,server块也可以包含自己的全局块,同时可以包含多个location块。在server全局块中,最常见的两个配置项是本虚拟主机的监听配置和本虚拟主机的名称或IP配置。


3.2.4.1 listen指令
listen 127.0.0.1:8000;  #只监听来自127.0.0.1这个IP,请求8000端口的请求
listen 127.0.0.1; #只监听来自127.0.0.1这个IP,请求80端口的请求(不指定端口,默认80)
listen 8000; #监听来自所有IP,请求8000端口的请求
listen *:8000; #和上面效果一样

#1. 多个虚拟主机可以同时监听同一个端口,但是server_name需要设置成不一样;
#2. default_server:假如通过Host没匹配到对应的虚拟主机,则通过这台虚拟主机处理。
#3. ssl:标识符,设置会话连接使用SSL模式进行,此标识符和Nginx服务器提供的HTTPS服务有关。

3.2.4.2 server_name指令

​对于name 来说,可以只有一个名称,也可以由多个名称并列,之间用空格隔开。每个名字就是一个域名,由两段或者三段组成,之间由点号“.”隔开。比如

#用于配置虚拟主机的名称。语法是:
server_name myserver.com www.myserver.com

​Nginx服务器规定,第一个名称作为此虚拟主机的主要名称。在name 中可以使用通配符“*”,但通配符只能用在由三段字符串组成的名称的首段或尾段,或者由两段字符串组成的名称的尾段,如:

server_name myserver.* *.myserver.com


​由于server_name指令支持使用通配符和正则表达式两种配置名称的方式,因此在包含有多个虚拟主机的配置文件中,可能会出现一个名称被多个虚拟主机的server_name匹配成功。那么,来自这个名称的请求到底要交给哪个虚拟主机处理呢?参考如下:

  1. 准确匹配server_name
  2. 通配符在开始时匹配server_name成功
  3. 通配符在结尾时匹配server_name成功
  4. 正则表达式匹配server_name成功

3.2.4.3 location块

​每个server块中可以包含多个location块。在整个Nginx配置文档中起着重要的作用,而且Nginx服务器在许多功能上的灵活性往往在location指令的配置中体现出来。地址定向、数据缓存和应答控制等功能都是在这部分实现。许多第三方模块的配置也是在location块中提供功能。

Tips:更多详情看后文!


4. 上手Nginx

4.1 搭建第一个网站

规划 详细说明
域名 www.yinjay.com
端口 80
站点目录 /app/code/www
首页文件 /app/code/www/index.html

开始进行配置

[root@web02 ~]# cd /etc/nginx/conf.d/
[root@web02 conf.d]# cp default.conf default.conf.bak  #备份默认配置
[root@web02 conf.d]# vim default.conf
[root@web02 conf.d]# cat default.conf   #新配置如下
server {
  listen 80;
  server_name www.yinjay.com;
  location / {
    root /app/code/www;
    index index.html;
  }
}

#创建目录和index.html文件
[root@web02 conf.d]# mkdir -p /app/code/www
[root@web02 conf.d]# echo www.yinjay.com > /app/code/www/index.html

进行语法检查并重新加载配置文件

[root@web02 conf.d]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@web02 conf.d]# systemctl reload nginx

在window宿主机上更改hosts文件,添加一条记录

10.0.0.8 www.yinjay.com

访问测试

image-20230301164410801


4.2 配置虚拟主机功能

​nginx虚拟主机,每一个虚拟主机就是一个server{}区域(端口,域名,站点目录),一个网站。在一个nginx中一般都会有多个虚拟主机(端口,不同的域名,不同的站点目录)。

配置多个虚拟主机的方式 含义 应用场景
基于域名的虚拟主机 不同的域名访问不同的虚拟主机 最广泛使用的
基于端口的虚拟主机 不同的端口访问不同的虚拟主机 一般因为安全修改下端口,不想让普通用户访问。
基于IP的虚拟主机 不同的ip访问不同的虚拟主机 用户必须通过指定的ip访问网站

4.2.1 基于域名的虚拟主机
域名 站点目录 端口
www.yinjay.com /app/code/www/ 80
game.yinjay.com /app/code/game/ 80
video.yinjay.com /app/code/video/ 80

首先创建目录和index.html文件

mkdir -p /app/code/{www,game,video}

echo www.yinjay.com > /app/code/www
echo game.yinjay.com > /app/code/game
echo video.yinjay.com > /app/code/video

配置文件如下:

[root@web02 ~]# cat /etc/nginx/conf.d/www.yinjay.com.conf
server {
  listen 80;
  server_name www.yinjay.com;
  location / {
    root /app/code/www;
    index index.html;
  }
}
[root@web02 ~]# cat /etc/nginx/conf.d/game.yinjay.com.conf
server {
  listen 80;
  server_name game.yinjay.com;
  location / {
    root /app/code/game;
    index index.html;
  }
}
[root@web02 ~]# cat /etc/nginx/conf.d/video.yinjay.com.conf
server {
  listen 80;
  server_name video.yinjay.com;
  location / {
    root /app/code/video;
    index index.html;
  }
}

检查配置并重新加载

[root@web02 ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@web02 ~]# systemctl reload nginx

修改window宿主机的host文件

10.0.0.8 www.yinjay.com game.yinjay.com video.yinjay.com

宿主机测试访问

image-20230301195525183


4.2.2 基于端口的虚拟主机

更改listen指令配置,记得配置检查和重新加载配置

[root@web02 ~]# cat /etc/nginx/conf.d/www.yinjay.com.conf
server {
  listen 8080;
  server_name www.yinjay.com;
  location / {
    root /app/code/www;
    index index.html;
  }
}

image-20230301200640326


4.2.3 基于ip的虚拟主机

在listen指令加多ip即可

server {
  listen 172.16.1.8:8848;
  server_name www.yinjay.com;
  location / {
    root /app/code/www;
    index index.html;
  }
}

4.3 设置只限域名访问

实现只能用域名来访问,如果用ip访问出现如下情况

image-20230301205041426

方法1

server {
  listen 80 default_server;
  server_name _;
  charset utf8;
  default_type text/plain;
  location / {
      return 200 "请使用域名访问!";
  }
}

server {
  listen 80;
  server_name www.yinjay.com;
  charset utf8;
  location / {
      root /app/code/www;
      index index.html;
  }
}
  1. 直接通过IP地址访问和通过域名访问,请求到达 nginx 时其实都是 IP 地址访问的(域名访问时会做域名解析成IP地址),不同的是直接通过IP地址访问时请求头中 HOST 字段是IP地址,而通过域名访问时请求头中 HOST 字段是域名。

  2. 直接通过IP地址访问时两个 server 块都能匹配上,但是第一个 server 块中 listen 指令使用了 default_server 参数,所以在两个都匹配的情况下,nginx 最终匹配了默认的。

  3. 通过域名访问时其实两个 server 块也都能匹配上,但是 nginx 根据它的匹配规则选择了 server_name 指令匹配的那个块,此时不会看 default_server 参数。

default_server 参数是在最终都可以匹配的情况下去选择这个默认的 server 块!


方法2

server {
  listen 80;
  server_name www.yinjay.com;
  charset utf8;
  default_type text/plain;

  if ($host != 'www.yinjay.com'){
      return 200 "请使用域名访问!";
}
  location / {
      root /app/code/www;
      index index.html;
  }
}
  1. 直接通过IP地址访问和通过域名访问,请求到达 nginx 时其实都是 IP 地址访问的(域名访问时会做域名解析成IP地址),不同的是直接通过IP地址访问时请求头中 HOST 字段是IP地址,而通过域名访问时请求头中 HOST 字段是域名。

  2. 直接通过IP地址访问时匹配上 server 块了,由于有 $host != 'www.yinjay.com' 判断最终返回 403。

  3. 通过域名访问时匹配上 server 块了,因为访问域名是 http://www.yinjay.com,所以最终返回正常。


4.4 Nginx核心模块

​模块:nginx中模块包含了多个指令,不同的功能都有不同的模块。这种对于模块的支持,让nginx进行扩展或根据要求进行开启或关闭模块即可。


#查询nginx当前版本
[root@web02 ~]# nginx -v
nginx version: nginx/1.22.1

#查询nginx已经开启的模块以及一些参数
[root@web02 ~]# nginx -V
nginx version: nginx/1.22.1
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (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'

nginx核心模块
log_module 访问日志模块
autoindex_module 目录列表/索引功能模块
with-http_ssl_module 用于实现https功能
with-http_stub_status_module 用于查看nginx状态
with-http_v2_module 用于实现http2.0功能
with-stream nginx负载均衡功能,4层负载均衡模块
with-http_realip_module 负载均衡,代理使用,记录用户真实ip地址

4.4.1 nginx日志功能
4.4.1.1 日志概述

​日志大致分为access.log和error.log,即访问日志和错误日志。具体的模块和指令如下表

对应的指令和模块 含义 属于的模块
log_format 设置/定义访问日志的格式 日志模块 ngx_http_log_module
acccess_log 指定访问日志位置和使用什么格式 日志模块 ngx_http_log_module
error_log 设置错误日志位置和级别 nginx核心模块 core_module

4.4.1.2 访问日志指令

通过log_format定义日志格式

log_format
Syntax(语法) log_format 格式名字 string要求的格式.. ...;
Default(默认) log_format combined "..."; #更多用main格式,可以自定义
Context(放哪) http 也就是只能在http{}里面

默认的日志格式配置

image-20230302105453781


日志格式的变量(nginx内置)

变量 含义
$remote_addr 客户端ip地址
$remote_user 远端的用户(用于认证的用户),大部分时候是空的
$time_local 当前时间: 格式
20/Apr/2022:09:26:48 +0800
日期/月份/年:时:分:秒 +时区
$request 用户http请求的起始行: GET /yinjay.txt HTTP/1.1
$status http状态码
$body_bytes_sent 服务端给客户端响应的时候,响应报文主体的大小(文件大小)
$http_referer 页面用户是从哪里跳转过来的,从百度、谷歌搜索,如果用户直接访问,这个值是空的"-"
$http_user_agent 用户的客户端(浏览器)标识
$http_x_forwarded_for 用于负载均衡中,记录用户的真实ip地址。(XFF头)
$request_method 请求方法:GET/POST
$request_uri 请求中的uri部分
$scheme 是http请求还是https http/https

4.4.1.3 access_log指定日志
access_log指令
语法 access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
access_log off; #开关日志功能
默认值 access_log logs/access.log combined;
放哪 http , server , location , if in location , limit_except

access_log额外选项
buffer 给访问日志设置个缓存(减轻磁盘压力)buffer=128kb buffer=1mb
把数据先临时放在内存中,定期/定量写入到磁盘中
gzip 对日志进行个压缩(如果使用先把日志改名,清空) 可以不配置
flush 每隔一段时间把日志写入到磁盘,flush=5s,使用flush要与buffer一起使用

4.4.1.4 每个网站都设置自己的访问日志
域名 访问日志
www.yinjay.com /var/log/nginx/www/www.yinjay.com-access.log
game.yinjay.com /var/log/nginx/game/game.yinjay.com-access.log
video.yinjay.com /var/log/nginx/video/video.yinjay.com-access.log

创建日志目录

mkdir -p /var/log/nginx/{www,game,video}

各虚拟主机配置

[root@web02 conf.d]# cat www.yinjay.com.conf
server {
  listen 80;
  server_name www.yinjay.com;
  access_log /var/log/nginx/www/www.yinjay.com-access.log main;
  location / {
    root /app/code/www;
    index index.html;
  }
}
[root@web02 conf.d]# cat game.yinjay.com.conf
server {
  listen 80;
  server_name game.yinjay.com;
  access_log /var/log/nginx/game/game.yinjay.com-access.log main;
  location / {
    root /app/code/game;
    index index.html;
  }
}
[root@web02 conf.d]# cat video.yinjay.com.conf
server {
  listen 80;
  server_name video.yinjay.com;
  access_log /var/log/nginx/video/video.yinjay.com-access.log main;
  location / {
    root /app/code/video;
    index index.html;
  }
}

检查配置并重新加载

[root@web02 conf.d]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@web02 conf.d]# systemctl reload nginx

访问测试

image-20230302112846264


查看日志目录和内容

image-20230302113120667


4.4.1.5 错误日志指令

​错误日志指定文件和错误级别,错误级别决定这错误日志的详细程度,级别越高显示的越多。默认的级别是error出现错误的时候才记录错误日志,一般推荐的级别notice。

级别从高到底,依次排序!debug, info, notice, warn, error, crit, alert,emerg


error_log指令
格式 error_log file [level ];
默认值 error_log logs/error.log error;
放哪 main(核心功能区) , http , mail , stream , server , location

Tips:如果需要每个虚拟主机设置错误日志,参考4.4.1.4的配置文件!


4.4.1.6 日志切割

​防止单个日志过大而定期对文件切割,主要有下列两种方法:

  • 方法01:通过系统配置即可logrotate命令+定时任务。
  • 方法02:手动mv日志,重启服务+定时任务。

利用logrotate对日志进行切割

[root@web02 www]# vim /etc/logrotate.d/nginx 

/var/log/nginx/*.log {  #被切割的文件路径/var/log/nginx/ 以.log结尾的文件
        daily       #每天切割
        missingok   #如果日志不存在,不报错
        rotate 20   #保留20次
        size +100M  # 超过100M时分割,单位K,M,G
        no compress #对切割后的日志不进行压缩
        dateext     #使用当前日期作为格式,需要和dateformat一起使用
        dateformat -%Y%m%d
        notifempty  #not if empty 如果日志是空的不切割
        create 640 nginx adm  #切割后的日志权限和所有者,用户组信息
        sharedscripts     #所有的文件切割之后只执行一次下面脚本
        postrotate  #切割后执行的命令/脚本
                if [ -f /var/run/nginx.pid ]; then
                        kill -USR1 `cat /var/run/nginx.pid`
                fi
        endscript
}

#以此类推编写脚本,就可以实现各虚拟主机的日志切割
/var/log/nginx/www/*.log {
        daily
        missingok
        rotate 20
        size +100M
        nocompress
        dateext
        dateformat -%Y%m%d-%s
        notifempty
        create 640 nginx adm
        sharedscripts
        postrotate
                if [ -f /var/run/nginx.pid ]; then
                        kill -USR1 `cat /var/run/nginx.pid`
                fi
        endscript

常用参数如下:

compress:通过gzip对转储以后的日志进行压缩
nocompress:不对日志进行gzip压缩处理
copytruncate:用于处理还在打开中的日志文件,以先拷贝再清空的方式对当前日志进行备份并截断操作;由于拷贝和清空之间有一个时间差,可能会丢失部分日志数据
nocopytruncate:备份日志文件但不进行截断操作
create mode owner group:轮转时指定创建新文件,可指定权限、属主和属组
nocreate:日志轮转后不创建新的日志文件
delaycompress:发生轮转的日志文件到下一次转储时才压缩
nodelaycompress:日志轮转同时进行压缩
missingok:如果日志丢失,忽略此日志不产生报错
errors address:轮转时产生的错误信息发送到指定的Email地址
ifempty:空日志也进行日志轮转
notifempty:空日志不进行轮转
olddir directory:轮转后的日志文件放入指定的目录,指定目录和当前日志文件需要在同一个文件系统
noolddir:轮转后的日志文件和当前日志文件放在同一个目录下
sharedscripts:所有日志都轮转后统一执行postrotate脚本
prerotate:在logrotate轮转之前需要执行的指令,如修改文件的属性
postrotate:在logrotate转储之后需要执行的指令,如重启(kill -HUP)服务
daily:指定轮转周期为每天
weekly:指定轮转周期为每周
monthly:指定轮转周期为每月
rotate count:指定日志文件删除之前轮转的次数,0:没有备份,5:保留5个备份
dateext:使用当期日期作为轮转日志的后缀名
dateformat .%s:配合dateext使用,紧跟在下一行出现,定义文件切割后的文件名,只支持 %Y %m %d %s 这四个参数
size(或minsize) log-size:当日志文件到达指定的大小时才轮转,log-size能指定bytes(缺省)及KB (sizek)或MB(sizem).
当日志文件 >= log-size 的时候就轮转
size = 5 或 size 5 (>= 5 个字节就轮转)
size = 100k 或 size 100k
size = 100M 或 size 100M

最后再配置一下定时任务

执行crontab –e
0 0 * * * /usr/sbin/logrotate -f /etc/logrotate.d/nginx #每天凌晨00:00自动执行日志切割任务

4.4.2 目录列表功能

​用户访问网站的时候,把网站站点目录的内容都列出来。以下两个是需要用到的指令。

autoindex指令 开启/关闭网站目录列表功能
格式 autoindex on | off;
默认值 autoindex off;
放在哪 http , server , location
autoindex_localtime指令 网页显示的时间与实际时间不符,需要开启这个指令
格式 autoindex_localtime on | off;
默认值 autoindex_localtime off;
放在哪 http , server , location

下面搭建一个属于自己的下载站试试

网站名字 站点目录 访问日志/错误日志
dl.yinjay.com /app/code/dl/ dl.yinjay.com-access.log
dl.yinjay.com-error.log

创建网站目录和日志目录

mkdir -p /app/code/dl/{public,vip,svip}
mkdir -p /var/log/nginx/dl/

编辑 /etc/nginx/conf.d/dl.yinjay.com.conf,内容如下:

server {
    listen 80;
    server_name dl.yinjay.com;
    root /app/code/dl;

    access_log /var/log/nginx/dl/dl.yinjay.com-access.log main;
    error_log /var/log/nginx/dl/dl.yinjay.com-error.log notice;

    autoindex on;
    autoindex_localtime on;

    location / {
        index index.html;
        if ($request_filename ~* ^.*?\.(txt|doc|pdf|rar|gz|zip|docx|exe|xlsx|ppt|pptx)$){
            add_header Content-Disposition: 'attachment;';
            }
  }
}

进行配置检查并加载配置文件,同时在window宿主机加上host记录

[root@web02 nginx]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@web02 nginx]# systemctl reload nginx


#window宿主机Host记录
10.0.0.8 dl.yinjay.com

进行测试

image-20230302194949781


创建测试文件

[root@web02 nginx]# echo public > /app/code/dl/public/public.txt
[root@web02 nginx]# echo vip > /app/code/dl/vip/vip.txt
[root@web02 nginx]# echo svip > /app/code/dl/svip/svip.txt

​此时,我们进行验证,会发现以上的配置在浏览器上是不生效的,因为浏览器自动去识别文件的后缀,当识别到pdf文件时,还是会打开文件在网页中识别内容。这样的话,我们需要修改和nginx.conf同级目录下的mime.types文件。

[root@web02 nginx]# vim /etc/nginx/mime.types
#增加下列一条
application/octet-stream                         txt pdf xml;

#Application/octet-stream是应用程序文件的默认值。意思是未知的应用程序文件,浏览器一般不会自动执行或询问执行。浏览器会像对待,设置了HTTP头Content-Disposition值为attachment的文件一样来对待这类文件,即浏览器会触发下载行为。

#说人话就是,浏览器并不认得这是什么类型,也不知道应该如何展示,只知道这是一种二进制文件,因此遇到content-type为application/octet-stream的文件时,浏览器会直接把它下载下来。这个类型一般会配合另一个响应头Content-Disposition,该响应头指示回复的内容该以何种形式展示,是以内联的形式(即网页或者网页的一部分),还是以附件的形式下载并保存到本地。

4.4.3 访问控制模块

使用nginx实现类似于防火墙(黑名单/白名单)功能。可以在这些区域http , server , location , limit_except配置。


限制10.0.0.0/24这个网络内的主机和172.16.1.1这个主机访问

server {
  listen 80;
  server_name www.yinjay.com;
  access_log /var/log/nginx/www/www.yinjay.com-access.log main;
  
  deny 10.0.0.0/24;
  deny 172.16.1.1;
  
  location / {
    root /app/code/www;
    index index.html;
  }
}

只允许10.0.0.8和172.16.1.1访问

server {
  listen 80;
  server_name www.yinjay.com;
  access_log /var/log/nginx/www/www.yinjay.com-access.log main;
  
  allow 10.0.0.8;
  allow 172.16.1.1;
  deny all;
  
  location / {
    root /app/code/www;
    index index.html;
  }
}

4.4.4 nginx状态模块

​显示nginx本身连接情况:未来用于监控nginx,配置如下:

[root@web02 nginx]# cat /etc/nginx/conf.d/status.yinjay.com.conf
server {
    listen 80;
    server_name status.yinjay.com;

    stub_status;


}

宿主机添加host后进行访问

image-20230302203357243

具体详解

image-20230302203504576


4.4.5 location指令匹配详解

lolcation规则详解可看此篇文章


4.5 nginx重写模块

模块指令 含义 应用场景
rewrite 用于使用正则匹配用户请求的uri,可以对uri进行处理。 支持正则,处理复杂的跳转
return 用于输出指定的状态码,实现初步跳转。 比如新旧网站跳转,http -> https ,或者是输出指定状态码
if 用于判断, 一般与nginx变量结合使用。 location不行了,又要进行判断就是用if
set 用于创建或修改nginx变量,一般是用户自定义变量。 需要创建一些组合变量

4.5.1 return指令
return指令
格式 return 状态码 要输出的内容;
return 状态码 url;
return 状态码;
放在哪 server , location,if

4.5.1.1 只要用户访问/admin 提示403
[root@web03 conf.d]# cat rewrite.yinjay.com.conf
server {
   listen 80;
   server_name rewrite.yinjay.com;
   root /app/code/rewrite;

   access_log /var/log/nginx/rewrite.yinjay.com-access.log main;
   error_log /var/log/nginx/rewrite.yinjay.com-error.log notice;

   location / {
       index index.html;

   }

   location /admin {
       return 403;
   }
}

image-20230314203538897


4.5.1.2 用户访问站点跳转 www.baidu.com

无论用户访问什么内容都去找百度对应的页面,访问rewrite.yinjay.com/hello.txt --> www.baidu.com/hello.txt

[root@web03 conf.d]# cat rewrite.yinjay.com.conf
server {
   listen 80;
   server_name rewrite.yinjay.com;
   root /app/code/rewrite;

   access_log /var/log/nginx/rewrite.yinjay.com-access.log main;
   error_log /var/log/nginx/rewrite.yinjay.com-error.log notice;

   return 302 http://www.baidu.com$request_uri ;

image-20230314204649758


4.5.1.3 用户默认访问http跳转到https
server {
listen 80;
server_name rewrite.yinjay.com;
return 302 https://rewrite.yinjay.com$request_uri;
}
server {
listen 443 ssl;
server_name rewrite.yinjay.com;
root /app/code/ssl;
location / {......}
ssl证书
ssl私钥
}

4.5.2 set指令
set指令
格式 set $变量名 变量内容;
放在哪 server , location,if , stream

4.5.2.1 让访问日志中可以记录用户访问的URL

修改nginx访问日志格式,变量内容:

$scheme      #http或https
$http_host   #域名部分
$request_uri #请求中的uri

修改配置文件

[root@web03 conf.d]# cat rewrite.yinjay.com.conf
server {
   listen 80;
   server_name rewrite.yinjay.com;
   root /app/code/rewrite;

   access_log /var/log/nginx/rewrite.yinjay.com-access.log main;
   error_log /var/log/nginx/rewrite.yinjay.com-error.log notice;

   set $all_url "$scheme://$http_host$request_uri";

   location / {
       index index.html;

   }

}

image-20230314211939989


查看日志

image-20230314212046012


4.5.3 rewrite指令
rewrite指令
格式 rewrite 正则匹配uri 替换成什么 [标记];
放哪 server , location , if

4.5.3.1 实现匹配uri内容然后进行跳转
[root@web03 ~]# cat /etc/nginx/conf.d/rewrite.yinjay.com.conf
server {
   listen 80;
   server_name rewrite.yinjay.com;
   root /app/code/rewrite;

   access_log /var/log/nginx/rewrite.yinjay.com-access.log main;
   error_log /var/log/nginx/rewrite.yinjay.com-error.log notice;

   rewrite (^.*$) http://www.baidu.com/s?wd=$1;

}

4.5.3.2 rewrite各种标记
rewrite标记
redirect 302 临时跳转,外部跳转。
rewrite处理完成后把处理后的请求发给用户,然后用户重新发出请求。
permanent 301 永久跳转,外部跳转。
rewrite处理完成后把处理后的请求发给用户,然后用户重新发出请求。
break 结束,rewrite处理完这个请求后,后面如果还有内容,不会处理,直接结束。
nginx内部跳转。
last rewrite处理完成这个请求后,新的请求会在nginx内部进行匹配与处理。
nginx内部跳转。

下面进行实验,看看这几种的区别

#进行以下配置
[root@web03 ~]# cat /etc/nginx/conf.d/flag.yinjay.com.conf
server {
    listen 80;
    server_name flag.yinjay.com;
    root /app/code/flag;
    access_log /var/log/nginx/flag.yinjay.com-access.log main;
    error_log /var/log/nginx/flag.yinjay.com-error.log notice;
    rewrite_log on;

    location / {
         rewrite /1.html /2.html ;
         rewrite /2.html /3.html ;
    }

    location /2.html {
         rewrite /2.html /3.html ;
    }

    location /3.html {
         rewrite /3.html /a.html ;

    }
}

#创建测试目录和文件
[root@web03 ~]# mkdir -p /app/code/flag
[root@web03 ~]# echo 1.html url > /app/code/flag/1.html
[root@web03 ~]# echo 2.html url > /app/code/flag/2.html
[root@web03 ~]# echo 3.html url > /app/code/flag/3.html
[root@web03 ~]# echo a.html url > /app/code/flag/a.html

访问/1.html显示a.html内容,因为当访问/1.html时只能落在location / ,然后/1.html替换成/2.html ,/2.html替换成/3.html。此时匹配到location /3.html命中,再/3.html替换成/a.html

image-20230315135342192

image-20230315140008775


在rewrite /1.html /2.html的时候加上标记break标记,会访问到哪个页面呢?访问到2.html,因为rewrite处理完这个请求后,后面如果还有内容,不会处理,直接结束。

image-20230315140308341


在rewrite /1.html /2.html的时候加上标记last标记,注意这一步修改下配置文件,创建新的页面b.html echo b.html > /app/code/flag/b.html

    location / {
         rewrite /1.html /2.html last;
         rewrite /2.html /3.html ;
    }

    location /2.html {
         rewrite /2.html /b.html ;
    }

    location /3.html {
         rewrite /3.html /a.html ;

    }
}

访问/1.html被匹配到location / ,然后进行/1.html替换成/2.html,遇到last,结束本块内的匹配。下一步/2.html与后面的location /2.html匹配,再/2.html替换成/b.html

image-20230315140729834

以上部分内容来源竹子爱熊猫、程序员自由之路、组团学博主,感谢分享知识干货!

posted @ 2023-09-05 21:45  YinJayChen  阅读(85)  评论(0编辑  收藏  举报