Nginx学习笔记

本文最后更新于:2023年6月29日 晚上

Nginx 学习笔记

最近一阵子经常使用到 Nginx ,对其中的一些配置和原理有了充分的认识,并且踩了许多坑,所以才有这篇文章用来记录。

一、基本使用

1. 安装

Windows 安装

进入 nginx 官方网站的下载页进行下载,选择最新版本下载即可,解压之后双击 nginx.exe 即可启动 nginx

Linux 安装 (以 Ubuntu 为例)

使用 apt 安装:

1
sudo apt install nginx

源码编译安装:

手动编译安装 nginx 需要依赖某些类库,所以先安装需要的依赖类库。

1
2
3
4
5
6
sudo apt-get install build-essential
sudo apt-get install libtool
sudo apt-get install libpcre3 libpcre3-dev
sudo apt-get install zlib1g-dev
sudo apt-get install openssl
sudo apt-get install gcc g++

解压下载好的 nginx 文件夹,然后进入解压后的目录,执行如下命令。

1
2
3
# 默认安装的路径是 /usr/local/nginx
# 如果不想安装在 /usr/local/nginx,用 --prefix 参数指定安装位置
./configure

执行安装操作

1
make && make install

2. 常用命令

下面是一些常用的 nginx 命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 启动,使用 conf 下的默认配置文件 nginx.conf
./nginx

# 使用特定配置文件
./nginx -c /root/nginx.conf

# 停止
./nginx -s quit

# 重新加载配置文件并且重启
./nginx -s reload

# 测试配置文件是否正确
./nginx -t

# 查看nginx编译参数及nginx版本
./nginx -V

3. 升级与回滚

3.1. 升级

这里的升级只涉及到服务器环境中 (Linux) 升级的操作。

普通升级

如果只是普通的升级,那么可以在停止升级版本之前 nginx 的前提下,更新会方便很多。

停止原来的的 nginx:

1
2
cd /usr/local/nginx/sbin
./nginx -s quit

编译新的 nginx ,编译之前,要查看旧的 nginx 是否有额外的编译参数并且备份旧的 nginx 执行文件,如果有则也需要一并复制过来。编译的时候尽量使用 make 而不是 make install ,make install 会执行安装命令,保险起见,使用 make 即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 检查是否有额外的编译参数
cd /usr/local/nginx/sbin && ./nginx -V

# 备份 nginx
mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.old

# 备份 配置文件
cp /usr/local/nginx/conf/nginx.conf /usr/local/nginx/conf/nginx.conf.bak

# 编译新的 nginx
cd /root/nginx-1.16.1/ && ./configure --prefix=/usr/local/nginx/
make

# 拷贝新的 nginx 执行文件到 /usr/local/nginx/sbin/
cp /root/nginx-1.16.1/obj/nginx /usr/local/nginx/sbin

# 启动新的 nginx
cp /usr/local/nginx/sbin/ && ./nginx

不停机升级

不停机的升级则稍微麻烦点,需要让 nginx 在不停止的情况下从旧版本过渡到新版本,但是好在 nginx 自身实现了平滑升级的操作。

下面是 nginx 支持 kill 的信号

nginx 主进程支持的信号:

  • TERM, INT 作用和nginx -s stop一致;
  • QUIT 作用和nginx -s quit一致;
  • HUP 作用和nginx -s reload一致
  • USR1 作用和nginx -s reopen一致;
  • USR2 平滑升级nginx
  • WINCH 平滑关闭工作进程;

nginx 工作进程支持的信号:

  • TERM, INT 快速停止
  • QUIT 优雅停止
  • USR1 重新开启新的日志文件
  • WINCH 异常终止调试(需要启用debug_points选项)

下面是一个 nginx 升级的步骤:

下载新版本 nginx 并解压,然后执行配置命令和编译命令。

1
2
3
4
5
6
7
8
9
# 以 nginx.1.14.2 升级 1.18.0 为例
tar -zxvf nginx-1.18.0 && cd nginx-1.18.0

# 执行 ./configure 命令,首先需要检查旧版本的 nginx 是否有额外的编译参数,如果有需要一并拷贝过来
# 默认的 prefix 是在 /usr/local/nginx,如果你的不是,则需要指定和旧 nginx 一样的位置
./configure

# 执行 make
make

备份旧的 nginx 和配置文件,这里可以直接使用 mv 命令,不影响目前 nginx 的运行。

1
2
mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.old
cp /usr/local/nginx/conf/nginx.conf /usr/local/nginx/conf/nginx.conf.bak

复制新版本编译的 nginx 到之前的安装路径中;新版本编译后的 nginx 在解压后的 nginx 的 obj 文件夹下。

1
cp obj/nginx /usr/local/nginx/sbin/.

其实这里可以仔细看看新版本文件夹下的 Makefile 文件,会发现自带一个 upgrade 命令。

1
2
3
4
5
6
7
8
upgrade:
/usr/local/nginx/sbin/nginx -t

kill -USR2 `cat /usr/local/nginx/logs/nginx.pid`
sleep 1
test -f /usr/local/nginx/logs/nginx.pid.oldbin

kill -QUIT `cat /usr/local/nginx/logs/nginx.pid.oldbin`

回到新版本的解压目录下,执行更新操作,即可完成 nginx 的不停机升级操作。

1
sudo make upgrade

3.2. 回滚

什么时候会需要进行 nginx 的回滚,当新版本的 nginx 不稳定,可能需要;这里的升级只涉及到服务器环境中 (Linux) 升级的操作;

普通回滚

如果是进行普通的回滚,那么步骤很简单,下面是步骤。

如果是旧版本 nginx 还在,那么直接停掉新版本的 nginx ,启动旧版本的 nginx 即可。

1
2
3
4
5
6
7
8
9
10
# 假设新旧版本 nginx 都在 /usr/local/nginx/sbin 下

# 停止新版本的 nginx
./nginx -s quit

# 备份新版本的 nginx 以防万一
mv nginx nginx.new

# 恢复旧版本的 nginx 并且启动
mv nginx.old nginx && ./nginx

不停机回滚

不停机的回滚如同不停机升级一样,需要使用到 nginx 的信号机制,这里需要提到前面nginx 的 make upgrade 操作;我们更新一般都是在服务器上进行更新于回滚,那么就可以不使用 make upgrade 命令,为什么呢,先看 make upgrade 命令做了什么。

1
2
3
4
5
6
7
8
upgrade:
/usr/local/nginx/sbin/nginx -t

kill -USR2 `cat /usr/local/nginx/logs/nginx.pid`
sleep 1
test -f /usr/local/nginx/logs/nginx.pid.oldbin

kill -QUIT `cat /usr/local/nginx/logs/nginx.pid.oldbin`

前面的指令都是正常的,但是最后一步,由于 USR2 信号会启动新的进程,但是旧版本的主进程是还在的,如果最后使用 -QUIT 信号,那么将会把旧版本的主进程彻底停掉,这个时候如果想要进行版本回退,那么则无法进行平滑回退,因为旧版本的 nginx 进程已经被退出了,所以我们选择在进行更新时不退出旧版本的进程,方便新版本使用时出现问题及时回滚。

下面是回滚的步骤,假设在升级的过程中:

1
2
3
4
5
6
7
8
9
10
11
12
# 给旧的 nginx 主进程发送热更新信号
kill -USR2 6789

# 关闭旧版本的 nginx 工作进程 (主进程保留)
kill -WINCH 6789

# 发送HUP信号给旧版本的主进程
kill -HUP 6789

# 关闭新版本的主进程
# 如果没有关闭,强制关闭新版本的主进程和工作进程
kill -QUIT 7890

二、配置文件

1. 配置文件结构

Nginx 配置文件结构是由多个块(Block)组成的,每个块包含一组指令(Directive),指令用来配置 Nginx 的行为。Nginx 配置文件结构如下:

全局块(Global Block):全局块是配置文件的第一部分,它包含全局指令,对整个 Nginx 服务器都生效。全局块中可以设置一些全局参数,如 worker_processes、pid 等。

Events 块:Events 块用来配置 Nginx 如何处理连接、事件、工作进程等底层参数。Events 块以 events { … } 开始,以 } 结束。在 Events 块中可以设置一些事件相关的参数,如 worker_connections 等。

Http 块:Http 块用来配置 HTTP 服务相关的指令,包括 HTTP 服务器、代理、缓存、负载均衡、安全等。Http 块以 http { … } 开始,以 } 结束。在 Http 块中可以设置一些 HTTP 相关的参数,如 server、upstream、location 等。

Server 块:Server 块用来配置一个虚拟主机,指定监听端口、域名、访问日志、错误日志、默认网站等。一个 Http 块可以包含多个 Server 块。Server 块以 server { … } 开始,以 } 结束。在 Server 块中可以设置一些虚拟主机相关的参数,如 listen、server_name、access_log、error_log 等。

Location 块:Location 块用来配置虚拟主机下的具体 URL 路径,指定访问该路径时的处理方式,如反向代理、缓存、重定向等。一个 Server 块可以包含多个 Location 块。Location 块以 location { … } 开始,以 } 结束。在 Location 块中可以设置一些路径相关的参数,如 proxy_pass、root、try_files 等。

注:有些配置属性可以在多个作用域中配置

2. 全局块

下面介绍一下全局块常用的属性:

user :指定 worker 的运行用户,默认是对应的用户名和用户组,可以重写此配置更改 nginx 执行的用户和用户组,举例:user root root; 在使用一些软件源安装时,此配置指定的用户和用户组是 nginx

work_processes :指定 nginx 工作进程的个数,默认是1,通常设置为 cpu 的核心数一致即可。

pid :nginx 进程 ID 文件的存放路径,如果是自己手动编译并且未指定安装位置的,默认位置是 /usr/local/nginx/logs/nginx.pid ,可以重写此配置更改存放路径。

error_log :记录服务器请求处理中的错误日志,此配置可以在 http/server/location 等作用域中配置。该配置的语法是:error_log file_path log_level ,日志级别可以是 debug, info, notice, warn, error, crit, alert, emerg,只有高于定义级别的错误日志才会被写入。

access_log :记录客户端的请求日志,此配置可以在 http/server/location 等作用域中配置。配置语法是:access_log filepath

3. Event 块

Event 块中的属性都写在 Event 块内,下面是一些常用的配置:

use :指定要使用的连接事件模型,nginx 默认根据系统使用最优的事件模型。当然也可以重写此配置指定事件模型。

work_connections :工作进程的最大连接数,默认是每台 nginx 的 work_processes * work_connections

multi_accept :是否允许每个工作进程接受多个网络连接,默认关闭 (off),可重写此配置打开 (multi_accept on) 。

4. Http 块

Http 块中的属性都写在 Http 块内,下面是一些常用的配置:

include :将另一个文件引入到当前配置中,nginx 默认引入了 mime.types,此文件设置了文件头对应的文件格式,如果没有则可以在 mime.types中新增,除此之外,include 指令要注意的是只能引入符合 http 作用域的配置文件包含的配置属性,否则会报错。

default_type:用来配置Nginx响应前端请求默认的MIME类型。

upstream :用于指定一组服务器,以便用于负载均衡,并且还可以设置不同的负载均衡策略。upstream 指定名字后,server 块中的 proxy_pass 使用 upstream 的别名即可。

1
2
3
4
5
upstream blog {
server 10.10.10.1 7890;
server 10.10.10.1 7891;
server 10.10.10.1 7892;
}

上面没配置负载均衡策略,则会使用默认的轮询策略进行负载均衡处理。下面是其他的负载均衡策略:

  1. 轮询(Round Robin):默认的负载均衡策略。Nginx 按照定义的后端服务器列表顺序依次分发请求,每个请求按顺序发送到下一个服务器。
  2. IP 哈希(IP Hash):根据客户端的 IP 地址对后端服务器进行哈希计算,将相同 IP 的请求发送到同一台服务器。这样可以确保同一客户端的请求都发送到同一个服务器,适用于需要保持会话一致性的场景。除了 IP Hash 之外,还有使用 URL Hash 的方式。
  3. 最少连接(Least Connections):将请求发送到当前连接数最少的服务器。这样可以确保将请求发送到负载较轻的服务器,以实现负载均衡。
  4. 加权轮询(Weighted Round Robin):为每个后端服务器分配一个权重值,根据权重值决定分发请求的比例。权重值越高的服务器将获得更多的请求。
  5. 加权最少连接(Weighted Least Connections):结合了加权和最少连接策略。根据服务器的权重值和当前连接数,动态计算每个服务器的有效权重,然后选择有效权重最高的服务器来处理请求。

5. Server 块

Server 块中的属性都写在 Server 块内,下面是一些常用的配置:

listen 监听指定的 IP 地址 + 端口

listen 8080 监听本机的8080

listen 127.0.0.1 监听本机的所有端口

listen *:8080 | *:80 监听所有IP的8080和80端口

server_name 指定客户端访问的域名

server_name 支持定义多个,如果匹配到第一个,那么则不会匹配后面的,否则进行逐个匹配。同时 server_name 还支持正则匹配;下面是例子。

1
2
3
4
5
6
7
server_name www.example.com example.com;

# 正则匹配
server_name ~^www\.a\..*$;

# 匹配无效域名,最优先被匹配
server _;

error_page 针对特定的错误码,进行错误页面配置

下面是一些配置实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 对 502 503 转发到 /50x.html /50x.html 通过 location 配置 
error_page 502 503 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}

# 甚至还可以把错误页面配置成 JSON 格式
error_page 403 /respon_403.json;
location = /respon_403.json {
default_type application/json;
return 403 '{"code":"403", "message":"Forbidden"}';
}

error_page 404 /respon_404.json;
location = /respon_404.json {
default_type application/json;
return 403 '{"code":"404", "message":"Not Found"}';
}

error_page 500 502 503 504 /respon_500.json;
location = /respon_500.json {
default_type application/json;
return 403 '{"code":"500", "message":"Server Error"}';
}

6. Location 块

location 块负责指定 用户访问的路径基于怎么样的匹配规则进行转发,下面是 location 的匹配规则与匹配顺序。越前优先级越高,优先匹配。

  1. 精确匹配:使用 = 前缀的 location 块会首先被匹配。例如:
1
2
3
location = /path {
// 配置 A
}

如果请求的路径正好是 /path,那么将会使用配置 A 处理该请求。

  1. 前缀匹配:使用 / 作为前缀的 location 块会按照定义的顺序进行匹配。例如:
1
2
3
4
5
6
7
location /path1 {
// 配置 B
}

location /path2 {
// 配置 C
}

如果请求的路径是 /path1/foo,那么将会使用配置 B 处理该请求。如果请求的路径是 /path2/bar,那么将会使用配置 C 处理该请求。

  1. 正则表达式匹配:使用 ~ 或 ~* 前缀的 location 块会按照定义的顺序进行匹配。例如:
1
2
3
4
5
6
7
location ~ /path/.*\.html$ {
// 配置 D
}

location ~ /path/.*\.txt$ {
// 配置 E
}

如果请求的路径是 /path/file.html,那么将会使用配置 D 处理该请求。如果请求的路径是 /path/file.txt,那么将会使用配置 E 处理该请求。

  1. 带修饰符的正则表达式匹配:带有 ~ 或 ~* 前缀和 ^ 或 ~^ 修饰符的 location 块会按照定义的顺序进行匹配。例如:
1
2
3
4
5
6
7
location ~* ^/path/ {
// 配置 F
}

location ~* ^/path/file {
// 配置 G
}

如果请求的路径是 /path/foo,那么将会使用配置 F 处理该请求。如果请求的路径是 /path/file.html,那么将会使用配置 G 处理该请求。

  1. 优先级匹配:如果存在多个匹配规则相同的 location 块,Nginx 将使用最先定义的 location 块。例如:
1
2
3
4
5
6
7
location /path {
// 配置 H
}

location /path {
// 配置 I
}

在上述示例中,无论请求的路径是什么,都将使用配置 H 处理该请求,因为配置 H 在配置 I 之前定义。

  1. location /:如果没有匹配到其他的 location 块,Nginx 将使用默认的 location / 块。例如:
1
2
3
location / {
// 默认配置
}

这将匹配所有未被其他 location 块匹配到的请求。


Nginx学习笔记
http://aim467.github.io/2023/06/29/Nginx学习笔记/
作者
Dedsec2z
发布于
2023年6月29日
更新于
2023年6月29日
许可协议