上章节中文件的讲解

目录

配置文件

1、nginx.conf

2、lab.conf:定义后端服务器组


配置文件

两个配置文件的关系可以把它们理解成:

  • nginx.conf:公司的"总规章制度"
  • lab.conf:某个具体网站的"工作规则"

加载关系:

nginx.conf

└── http

└── include /etc/nginx/conf.d/*.conf

└── lab.conf

├── upstream

└── server

└── location

nginx.conf 最后一行加载了 conf.d 目录中的配置,所以 lab.conf 实际上会被插入 http 块内。

1、nginx.conf

(1)详解

文件位置:conf/nginx.conf

① Worker 进程数量
bash 复制代码
worker_processes auto;

Nginx 通常有两类进程:

Master 主进程

├── Worker 1

├── Worker 2

├── Worker 3

└── Worker 4

a. Master 进程

负责:

  • 读取配置
  • 创建 Worker
  • 接收 reload/stop 信号
  • 平滑更新配置

b. Worker 进程

负责:

  • 接收请求
  • 返回静态文件
  • 转发请求
  • 写日志

auto 表示让 Nginx 根据 CPU 数量自动决定 Worker 数量。

在 WSL 中,可以查看:podman exec nginx-lab ps

② 错误日志
bash 复制代码
error_log /var/log/nginx/error.log warn;

含义是:

  • 错误日志路径:/var/log/nginx/error.log
  • 日志级别:warn

常见日志级别由详细到严重,大致为:

debug → info → notice → warn → error → crit → alert → emerg

使用 warn 时,会记录警告以及更严重的问题。

例如:

  • 后端连接失败
  • 后端响应超时
  • 请求被限流
  • 文件不存在
  • 配置或运行异常

项目把容器里的日志目录映射到了本机:

  • 容器:/var/log/nginx/
  • 本机:~/nginx-podman-lab/logs/

所以可以直接查看:tail -f ~/nginx-podman-lab/logs/error.log

③ PID 文件
bash 复制代码
pid /var/run/nginx.pid;

PID 是进程编号。

Nginx 把 Master 进程编号写到这个文件中,例如:26

当执行:nginx -s reload

Nginx 会通过 PID 找到 Master 进程,然后向它发送重新加载配置的信号。

一般不需要手动修改这一项。

events
bash 复制代码
events {
    worker_connections 1024;
    multi_accept on;
}

这里管理网络连接。

a. worker_connections 1024

表示每个 Worker 最多可以同时打开大约 1024 个连接。

假设有 4 个 Worker,理论连接上限大致为:

4 × 1024 = 4096

但不能简单地将它当成"最多 4096 个用户",因为一次反向代理通常涉及两个连接:

用户 ←连接1→ Nginx ←连接2→ 后端

实际容量还会受到以下因素限制:

  • Linux 文件描述符上限
  • CPU
  • 内存
  • 后端处理能力
  • 长连接数量

本实验中的 1024 足够使用。

b. multi_accept on

当有很多新连接同时到来时,允许 Worker 一次接受多个连接。

大白话:

门口同时来了很多顾客,接待员可以连续接待,不必每次只领一个人。

生产环境中是否开启需要结合负载测试,本实验主要用于展示。

(2)http 块详细讲解

bash 复制代码
http {
    ...
}

所有普通 HTTP/HTTPS 网站配置通常都放在这里。

① 文件类型表
bash 复制代码
include /etc/nginx/mime.types;

default_type application/octet-stream;

a. mime.types

它告诉浏览器不同文件是什么类型:

.html → text/html

.css → text/css

.js → application/javascript

.png → image/png

如果没有正确类型,浏览器可能无法正常解析文件。

b. default_type

如果 Nginx 不认识某个文件扩展名,就使用:application/octet-stream

它表示:

这是一个普通二进制文件,具体类型不确定。

② 隐藏 Nginx 版本
bash 复制代码
server_tokens off;

默认错误页面或响应头可能显示:nginx/1.27.5

关闭后通常只显示:nginx

这样可以减少版本信息暴露。

但它只是基础安全设置,不代表服务器因此就绝对安全。

③ 高效发送文件
bash 复制代码
sendfile on;

tcp_nopush on;

a. sendfile on

普通发送文件过程可能是:磁盘 → 程序内存 → 网络

开启 sendfile 后,Linux 可以更高效地把文件数据交给网络层,减少不必要的数据复制。

适合:

  • HTML
  • CSS
  • JavaScript
  • 图片
  • 下载文件

b. tcp_nopush on

配合 sendfile 使用,尽量把数据凑成较完整的数据包后再发送。

大白话:

送货时尽量装满一车再发,而不是一个小包裹就发一辆车。

④ 客户端长连接
bash 复制代码
keepalive_timeout 65;

浏览器访问网页时,通常需要请求多个文件:

index.html

style.css

app.js

图片

如果没有长连接,每个文件可能都需要重新建立 TCP 连接。

开启 Keepalive 后:

建立一次连接

├── 请求 index.html

├── 请求 style.css

├── 请求 app.js

└── 暂时保留连接

65 表示连接空闲约 65 秒后关闭。

注意:这是客户端到 Nginx 的长连接设置,不是 Nginx 到后端的连接池。

⑤ 上传大小限制
bash 复制代码
client_max_body_size 10m;

客户端请求体最大为 10MB。

主要影响:

  • 文件上传
  • 大型 JSON
  • 表单提交

超过限制时,Nginx 通常返回:413 Request Entity Too Large

这是 http 级别的默认值,也可以在特定 serverlocation 中覆盖。

(3)Gzip 压缩

bash 复制代码
gzip on;

gzip_comp_level 5;

gzip_min_length 256;

gzip_types text/plain text/css application/json application/javascript application/xml text/xml;

① gzip on

开启响应压缩。

例如原本一个 CSS 文件有 100KB,压缩后可能只有 20KB。

过程如下:

Nginx 原始内容

↓ gzip 压缩

较小的数据

↓ 网络传输

浏览器自动解压

② gzip_comp_level 5

压缩等级为 5。

范围通常是 1~9:

  • 等级越高:文件可能越小
  • 等级越高:消耗的 CPU 越多

5 是比较平衡的实验值。

③ gzip_min_length 256

小于 256 字节的内容不压缩。

因为特别小的内容压缩收益很低,反而增加处理成本。

④ gzip_types

指定需要压缩的响应类型:

text/plain

text/css

application/json

application/javascript

application/xml

text/xml

图片一般不用再 gzip,因为 PNG、JPEG 等通常已经压缩。

验证是否压缩:

bash 复制代码
curl -I \
-H 'Accept-Encoding: gzip' \
http://127.0.0.1:18080/assets/style.css

如果生效,响应中可以看到:Content-Encoding: gzip

(4)限流区域

bash 复制代码
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=5r/s;

这只是定义限流规则和存储区域,还没有真正应用到请求。

a. $binary_remote_addr

表示客户端 IP 的二进制形式。

Nginx 按 IP 分别计数:

IP 192.168.1.10 → 自己的计数

IP 192.168.1.11 → 自己的计数

使用二进制形式是为了节省内存。

b. zone=api_limit:10m

创建一个名为 api_limit 的共享内存区域,大小为 10MB。

Worker 进程会在这里共同记录:哪个 IP 最近发了多少请求

这里的 10m 不是"允许 10MB 流量",而是用于保存限流状态的内存大小。

c. rate=5r/s

每个 IP 平均每秒允许 5 个请求。

真正使用这个规则的位置在 lab.conf

bash 复制代码
limit_req zone=api_limit burst=10 nodelay;

可以理解成:

limit_req_zone → 创建限流器

limit_req → 在某个接口上启用限流器

(5)访问日志格式

bash 复制代码
log_format lab '$remote_addr - [$time_local] "$request" '
'status=$status '
'rt=$request_time '
'urt=$upstream_response_time '
'upstream=$upstream_addr '
'us=$upstream_status '
'ref="$http_referer" '
'ua="$http_user_agent"';

这里定义了一个名为 lab 的日志格式。

① $remote_addr

客户端 IP。

在 Podman实验里,可能看到容器网络地址。

② $time_local

Nginx 收到请求的时间。

③ $request

完整请求行,例如:GET /api/info HTTP/1.1

④ $status

Nginx 最终返回的状态码:

200 正常

404 地址不存在

413 上传过大

502 后端异常

503 限流或暂不可用

504 后端响应超时

⑤ $request_time

从 Nginx 收到请求,到发送完响应的总时间。

日志里写成:rt=0.015

表示整个请求用了 0.015 秒。

⑥ $upstream_response_time

后端响应耗时:urt=0.012

如果请求是静态文件,没有经过后端,通常显示 -

⑦ $upstream_addr

请求交给了哪个后端:upstream=10.89.0.2:8000

⑧ $upstream_status

后端返回给 Nginx 的状态码。

例如:us=200

注意:

  • $status:Nginx 最终返回给用户的状态
  • $upstream_status:后端返回给 Nginx 的状态

二者不一定相同。

⑨ $http_referer

用户从哪个页面进入当前地址。

⑩ $http_user_agent

客户端信息,例如浏览器或 curl。

(6)启用访问日志

bash 复制代码
access_log /var/log/nginx/access.log lab;

含义:

  • 日志写入 /var/log/nginx/access.log
  • 使用刚才定义的 lab 格式

查看:tail -f ~/nginx-podman-lab/logs/access.log

(7)加载网站配置

bash 复制代码
include /etc/nginx/conf.d/*.conf;

加载 conf.d 目录下所有 .conf 文件。

本实验通过 Podman 挂载后,加载的是:conf/conf.d/lab.conf

这种拆分方式可以让一个 Nginx 管理多个网站:

conf.d/

├── app.conf

├── api.conf

├── admin.conf

└── lab.conf

2、lab.conf:定义后端服务器组

bash 复制代码
upstream app_backend {
    least_conn;
    keepalive 16;
    server backend-a:8000 weight=3 max_fails=2 fail_timeout=10s;
    server backend-b:8000 weight=1 max_fails=2 fail_timeout=10s;
}

upstream 表示一组后端服务器。

名字是:app_backend

后面可以通过下面的写法使用它:proxy_pass http://app_backend;

(1)backend-abackend-b

它们是 Podman 容器名称。

三个容器加入了相同网络:nginx-lab-net

Podman 内部 DNS 会把:

backend-a → A 容器的内部 IP

backend-b → B 容器的内部 IP

所以 Nginx 不需要写死 IP。

(2)least_conn

bash 复制代码
least_conn;

表示优先把新请求交给当前连接较少的后端。

例如:

A 当前有 10 个连接

B 当前有 2 个连接

新请求通常更倾向于交给 B。

如果不写负载均衡算法,默认使用轮询。

(3)keepalive 16

bash 复制代码
keepalive 16;

让每个 Worker 最多保留一定数量的空闲上游长连接。

没有连接池时:每次请求 → 新建后端连接 → 请求结束 → 关闭

使用连接池后:建立连接 → 请求结束 → 暂时保留 → 后续请求复用

好处:

  • 减少 TCP 建连成本
  • 降低后端压力
  • 提高性能

这里还需要在反代位置使用:

bash 复制代码
proxy_http_version 1.1;

proxy_set_header Connection "";

否则连接复用可能无法按预期工作。

(4)后端定义

bash 复制代码
server backend-a:8000 weight=3 max_fails=2 fail_timeout=10s;

server backend-b:8000 weight=1 max_fails=2 fail_timeout=10s;

① weight

A 权重 3,B 权重 1。

大体上表示 A 承担更多流量,但因为这里同时使用了 least_conn,实际选择还会考虑当前连接数,并不能机械理解成每四个请求一定是 A、A、A、B。

② max_fails=2

如果在指定时间内连续发生一定数量的失败,Nginx 会暂时认为该节点不可用。

③ fail_timeout=10s

它有两个相关作用:

  • 统计失败的时间窗口
  • 达到失败次数后,暂时避开该节点约 10 秒

这属于被动健康检查:

先有真实请求失败

Nginx 记录失败

达到 max_fails

暂时少选或不选该后端

它不是主动定时访问 /health 的健康检查。

(5)server:定义一个网站

bash 复制代码
server {
    listen 80;
    server_name localhost lab.local;
}

① listen 80

Nginx 容器内部监听 80 端口。

Podman做了端口映射:电脑 18080 → Nginx 容器 80

所以浏览器访问:http://127.0.0.1:18080

最终会到达容器的 80 端口。

② server_name

server_name localhost lab.local;

表示这个网站希望处理的域名是:

localhost

lab.local

本实验只有一个 server,因此使用 127.0.0.1 通常也会落到这里。

企业中可能有多个 server

server_name api.company.com;

server_name admin.company.com;

server_name www.company.com;

Nginx 根据请求中的 Host 选择对应网站。

(6)健康检查 /healthz

bash 复制代码
location = /healthz {
    access_log off;
    default_type text/plain;
    return 200 "ok\n";
}

① location = /healthz

location 根据 URL 路径决定如何处理请求。

= 表示精确匹配:

/healthz → 匹配

/healthz/ → 不匹配

/healthz/test → 不匹配

精确匹配优先级非常高。

② access_log off

健康检查通常每几秒执行一次,如果全部记录,访问日志会出现大量无价值内容,所以这里关闭访问日志。

错误仍然可以进入错误日志。

③ default_type text/plain

告诉客户端返回内容是普通文本。

④ return 200 "ok\n"

Nginx 直接返回:

HTTP 状态码:200

内容:ok

请求不会经过后端。

(7)静态网站

bash 复制代码
root /usr/share/nginx/html;

index index.html;

① root

设置静态文件根目录。

Podman把项目的 html 目录挂载到了:/usr/share/nginx/html

因此:

请求 /app.js

→ /usr/share/nginx/html/app.js

请求 /assets/style.css

→ /usr/share/nginx/html/assets/style.css

② index index.html

访问目录 / 时,默认查找:index.html

(8)try_files 和 SPA

bash 复制代码
location / {

    try_files $uri $uri/ /index.html;

}

location / 是最宽泛的前缀匹配,大多数请求都能匹配它。

try_files 按顺序尝试:

  1. $uri:有没有同名文件
  2. $uri/:有没有同名目录
  3. /index.html:都没有时返回首页

例如请求:/assets/style.css

Nginx 查到文件后直接返回。

请求:/user/profile

磁盘没有这个文件,于是返回:/index.html

这适合 Vue、React 等单页应用,因为 /user/profile 可能是前端路由,不是真实文件。

(9)静态资源缓存

bash 复制代码
location /assets/ {
    expires 7d;
    add_header Cache-Control "public";
    access_log off;
}

这个规则匹配:

  • /assets/style.css
  • /assets/logo.png

① expires 7d

告诉浏览器资源可以缓存 7 天。

这样用户第二次访问时,可以直接使用本地缓存,减少请求。

② Cache-Control "public"

表示该资源允许被浏览器、CDN 等公共缓存保存。

③ access_log off

静态资源请求很多,实验中关闭日志以减少干扰。

生产环境是否关闭,要根据审计和排障需求决定。

(10)核心反向代理 /api/

bash 复制代码
location /api/ {
    limit_req zone=api_limit burst=10 nodelay;
    proxy_pass http://app_backend/;
    ...
}

它匹配:

  • /api/info
  • /api/health
  • /api/slow

① 启用限流

bash 复制代码
limit_req zone=api_limit burst=10 nodelay;

使用 nginx.conf 中定义的:api_limit

a. burst=10

允许短时间额外突发约 10 个请求。

可以理解成:

  • 正常速度:每秒 5 个
  • 临时允许一个小队列/桶承受突发
  • 超出后拒绝请求

b. nodelay

突发额度内的请求立即处理,不让它们排队慢慢等待。

超过额度后,本实验通常返回 503。

② proxy_pass 尾斜杠

bash 复制代码
proxy_pass http://app_backend/;

这里末尾有 /

请求:/api/info

转发给后端时变成:/info

也就是 /api/ 前缀被替换成 /

这是本配置中非常重要的知识点。

③ 上游使用 HTTP/1.1

bash 复制代码
proxy_http_version 1.1;
proxy_set_header Connection "";

默认情况下,上游连接可能不按预期保持。

使用 HTTP/1.1 并清空 Connection 请求头,有助于复用前面 upstream 中配置的 Keepalive 连接。

这里的空字符串表示:

不要把这个请求头传给后端。

(11)反向代理请求头

bash 复制代码
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

① Host $host

告诉后端,用户访问的主机名是什么。

例如:lab.local

② X-Real-IP $remote_addr

告诉后端,Nginx 看到的客户端 IP 是什么。

③ X-Forwarded-For

记录代理链路中的客户端 IP。

例如:用户 → CDN → Nginx → 后端

它可能类似:203.0.113.10, 10.0.0.5

$proxy_add_x_forwarded_for 会保留已有内容,再追加当前客户端地址。

④ X-Forwarded-Proto $scheme

告诉后端用户原本使用的协议:http

如果以后增加 HTTPS,它可能是:https

后端生成跳转地址、Cookie 或外部链接时经常需要它。

(12)反向代理超时

bash 复制代码
proxy_connect_timeout 3s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;

① proxy_connect_timeout

Nginx 连接后端最多等待 3 秒。

例如后端端口无法连接,等待超过时间后放弃。

② proxy_send_timeout

Nginx 向后端发送请求数据时,连续写数据的等待超时。

它并不是整个请求的绝对总时长。

③ proxy_read_timeout

Nginx 等待后端返回数据的间隔超时。

如果后端在指定时间内一直没有返回新数据,Nginx 会终止请求。

普通 API 使用 30 秒只是实验值,生产中应该根据业务特点设置。

(13)故意制造 504 的 /timeout/

bash 复制代码
location /timeout/ {
    proxy_pass http://app_backend/;
    ...
    proxy_connect_timeout 1s;
    proxy_read_timeout 1s;
}

访问:/timeout/slow

因为 proxy_pass 带尾斜杠,后端收到:/slow

后端程序故意等待约 5 秒,但 Nginx 只允许连续等待 1 秒:

后端等待 5 秒、Nginx 只等 1 秒 → 504 Gateway Timeout

这里主要用来学习如何观察超时和错误日志,不能直接照搬到生产配置。

(14)/raw/ 演示尾斜杠区别

bash 复制代码
location /raw/ {
    proxy_pass http://app_backend;
}

注意这里没有尾斜杠。

访问:/raw/info

后端收到的仍然是:/raw/info

而不是 /info

后端没有 /raw/info 接口,所以返回 404。

对比:

/api/info + proxy_pass .../ → 后端收到 /info

/raw/info + proxy_pass ... → 后端收到 /raw/info

(15)精确匹配 /whoami

bash 复制代码
location = /whoami {
    default_type application/json;
    return 200 '{"via":"nginx-exact-location","hint":"location = has highest priority"}\n';
}

访问:/whoami

Nginx 直接返回 JSON,不访问后端,也不查找静态文件。

它用于演示:location = /whoami 比普通的 location / 优先级更高。

但访问 /whoami/test 不会匹配精确规则,而会进入 location /

(16)完整请求流程

① 请求首页

GET /

→ server 监听 80

→ 匹配 location /

→ try_files 找到 index.html

→ Nginx 返回静态网页

② 请求 CSS

GET /assets/style.css

→ 匹配 location /assets/

→ 从磁盘读取 CSS

→ 添加 7 天缓存头

→ 返回浏览器

③ 请求 API

GET /api/info

→ 匹配 location /api/

→ 检查限流

→ 去掉 /api/ 前缀

→ least_conn 选择 A 或 B

→ 转发 /info

→ 后端返回 JSON

→ Nginx 记录 upstream 和耗时

→ 返回浏览器

④ 请求慢接口

GET /timeout/slow

→ 匹配 location /timeout/

→ 转发后端 /slow

→ 后端等待 5 秒

→ Nginx 等待 1 秒后超时

→ 返回 504

⑤ 请求 /raw/info

GET /raw/info

→ 匹配 location /raw/

→ 保留完整路径 /raw/info

→ 后端没有该接口

→ 返回 404

(17)修改配置的正确步骤

先检查语法:podman exec nginx-lab nginx -t

成功后平滑加载:podman exec nginx-lab nginx -s reload

合并执行:

podman exec nginx-lab nginx -t &&

podman exec nginx-lab nginx -s reload

查看最终完整配置:podman exec nginx-lab nginx -T

查看实时日志:

tail -f logs/access.log

tail -f logs/error.log

核心:

nginx.conf:全局能力

lab.conf:网站与路由规则

upstream:后端名单

server:一个网站

location:不同 URL 怎么处理

proxy_pass:请求转给谁

相关推荐
进击的丸子2 小时前
APP人脸识别增值版Harmony Demo实操与关键代码解析
前端·程序员·harmonyos
a1117762 小时前
唯美花朵风格的黑胶唱片音乐播放器
前端·css·css3
Hilaku2 小时前
工作 5 年后,决定你薪资上限的究竟是什么?
前端·javascript·程序员
爱分享的程序猿-Clark2 小时前
【前端分享】vue3 有 keep-alive属性吗?
前端
Revolution612 小时前
页面更新后为什么出现 Loading chunk failed:旧页面如何请求了已删除的构建产物
前端·面试·前端工程化
JavaGuide2 小时前
GitHub 9.8 万 Star!把整个代码仓库变成知识图谱,这个 AI Coding 工具太适合 Claude Code / Codex 了
前端·后端·ai编程
hunterandroid3 小时前
[鸿蒙从零到一] HarmonyOS 通知与提醒实战:消息发布、点击跳转与定时触达
前端
Lxinz3 小时前
vscode调试ts代码思路
前端
极梦网络无忧3 小时前
real-ai-editor:一款轻量、智能的纯前端 AI 富文本与 Markdown 编辑器
前端·人工智能·编辑器